rustdoc: pretty-print Unevaluated expressions in types.
Fixes #44555.
r? @nikomatsakis
[submodule "src/tools/clippy"]
path = src/tools/clippy
url = https://github.com/rust-lang-nursery/rust-clippy.git
+[submodule "src/tools/rustfmt"]
+ path = src/tools/rustfmt
+ url = https://github.com/rust-lang-nursery/rustfmt.git
fast_finish: true
include:
# Images used in testing PR and try-build should be run first.
- - env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1
- - env: IMAGE=dist-x86_64-linux DEPLOY=1 ALLOW_TRY=1
+ - env: IMAGE=x86_64-gnu-llvm-3.7 RUST_BACKTRACE=1
+ if: type = pull_request OR branch = auto
+
+ - env: IMAGE=dist-x86_64-linux DEPLOY=1
+ if: branch = try OR branch = auto
# "alternate" deployments, these are "nightlies" but don't have assertions
# turned on, they're deployed to a different location primarily for projects
# which are stuck on nightly and don't want llvm assertions in the artifacts
# that they use.
- env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1
+ if: branch = auto
+
- env: >
RUST_CHECK_TARGET=dist
RUST_CONFIGURE_ARGS="--enable-extended --enable-profiler"
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
+ NO_LLVM_ASSERTIONS=1
+ NO_DEBUG_ASSERTIONS=1
os: osx
osx_image: xcode7
+ if: branch = auto
# macOS builders. These are placed near the beginning because they are very
# slow to run.
SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.8
MACOSX_STD_DEPLOYMENT_TARGET=10.7
+ NO_LLVM_ASSERTIONS=1
+ NO_DEBUG_ASSERTIONS=1
os: osx
osx_image: xcode8.2
+ if: branch = auto
+
- env: >
RUST_CHECK_TARGET=check
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.8
MACOSX_STD_DEPLOYMENT_TARGET=10.7
+ NO_LLVM_ASSERTIONS=1
+ NO_DEBUG_ASSERTIONS=1
os: osx
osx_image: xcode8.2
+ if: branch = auto
# OSX builders producing releases. These do not run the full test suite and
# just produce a bunch of artifacts.
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
+ NO_LLVM_ASSERTIONS=1
+ NO_DEBUG_ASSERTIONS=1
os: osx
osx_image: xcode7
+ if: branch = auto
+
- env: >
RUST_CHECK_TARGET=dist
RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler"
RUSTC_RETRY_LINKER_ON_SEGFAULT=1
SCCACHE_ERROR_LOG=/tmp/sccache.log
MACOSX_DEPLOYMENT_TARGET=10.7
+ NO_LLVM_ASSERTIONS=1
+ NO_DEBUG_ASSERTIONS=1
os: osx
osx_image: xcode7
+ if: branch = auto
# Linux builders, remaining docker images
- env: IMAGE=arm-android
+ if: branch = auto
- env: IMAGE=armhf-gnu
+ if: branch = auto
- env: IMAGE=cross DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-aarch64-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-android DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-arm-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-armhf-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-armv7-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-fuchsia DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-i686-freebsd DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-i686-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-mips-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-mips64-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-mips64el-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-mipsel-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-powerpc-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-powerpc64-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-powerpc64le-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-s390x-linux DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-x86_64-freebsd DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-x86_64-musl DEPLOY=1
+ if: branch = auto
- env: IMAGE=dist-x86_64-netbsd DEPLOY=1
+ if: branch = auto
- env: IMAGE=asmjs
+ if: branch = auto
- env: IMAGE=i686-gnu
+ if: branch = auto
- env: IMAGE=i686-gnu-nopt
+ if: branch = auto
# - env: IMAGE=wasm32 issue 42646
+ # if: branch = auto
- env: IMAGE=x86_64-gnu
+ if: branch = auto
- env: IMAGE=x86_64-gnu-full-bootstrap
+ if: branch = auto
- env: IMAGE=x86_64-gnu-aux
+ if: branch = auto
- env: IMAGE=x86_64-gnu-debug
+ if: branch = auto
- env: IMAGE=x86_64-gnu-nopt
+ if: branch = auto
- env: IMAGE=x86_64-gnu-distcheck
+ if: branch = auto
- env: IMAGE=x86_64-gnu-incremental
+ if: branch = auto
env:
global:
- - SCCACHE_BUCKET=rust-lang-ci-sccache
+ - SCCACHE_BUCKET=rust-lang-ci-sccache2
+ - SCCACHE_REGION=us-west-1
- AWS_ACCESS_KEY_ID=AKIAJAMV3QAMMA6AXHFQ
# AWS_SECRET_ACCESS_KEY=...
- secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo="
before_install:
- # If we are building a pull request, do the build if $ALLOW_PR == 1
- # Otherwise, do the build if we are on the auto branch, or the try branch and $ALLOW_TRY == 1
- - >
- if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then
- if [[ "$ALLOW_PR" == "1" ]]; then
- export SKIP_BUILD=false;
- else
- export SKIP_BUILD=true;
- fi;
- elif [[ "$TRAVIS_BRANCH" == "auto" || ( "$ALLOW_TRY" == "1" && "$TRAVIS_BRANCH" == "try" ) ]]; then
- export SKIP_BUILD=false;
- else
- export SKIP_BUILD=true;
- fi
- - >
- if [[ "$SKIP_BUILD" == false ]]; then
- zcat $HOME/docker/rust-ci.tar.gz | docker load || true
- fi
+ - zcat $HOME/docker/rust-ci.tar.gz | docker load || true
- mkdir -p $HOME/rustsrc
install:
- - >
- if [[ "$SKIP_BUILD" == true ]]; then
- echo echo skipping, not a full build > $HOME/stamp &&
- chmod +x $HOME/stamp &&
- export PATH=$PATH:$HOME;
- else
- case "$TRAVIS_OS_NAME" in
+ - case "$TRAVIS_OS_NAME" in
linux)
travis_retry curl -fo $HOME/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-unknown-linux-musl &&
chmod +x $HOME/stamp &&
travis_retry curl -fo /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin &&
chmod +x /usr/local/bin/stamp
;;
- esac
- fi
+ esac
before_script:
- >
secure: "kUGd3t7JcVWFESgIlzvsM8viZgCA9Encs3creW0xLJaLSeI1iVjlJK4h/2/nO6y224AFrh/GUfsNr4/4AlxPuYb8OU5oC5Lv+Ff2JiRDYtuNpyQSKAQp+bRYytWMtrmhja91h118Mbm90cUfcLPwkdiINgJNTXhPKg5Cqu3VYn0="
on:
branch: try
- condition: $DEPLOY = 1 && $ALLOW_TRY = 1
+ condition: $DEPLOY = 1
# this is the same as the above deployment provider except that it uploads to
# a slightly different directory and has a different trigger
* Magenta, **B**-prefixed labels identify bugs which are **blockers**.
+* Dark blue, **beta-** labels track changes which need to be backported into
+ the beta branches.
+
+* Light purple, **C**-prefixed labels represent the **category** of an issue.
+
* Green, **E**-prefixed labels explain the level of **experience** necessary
to fix the issue.
+* The dark blue **final-comment-period** label marks bugs that are using the
+ RFC signoff functionality of [rfcbot][rfcbot] and are currenty in the final
+ comment period.
+
* Red, **I**-prefixed labels indicate the **importance** of the issue. The
[I-nominated][inom] label indicates that an issue has been nominated for
prioritizing at the next triage meeting.
+* The purple **metabug** label marks lists of bugs collected by other
+ categories.
+
+* Purple gray, **O**-prefixed labels are the **operating system** or platform
+ that this issue is specific to.
+
* Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
are only assigned during triage meetings, and replace the [I-nominated][inom]
label.
-* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
+* The gray **proposed-final-comment-period** label marks bugs that are using
+ the RFC signoff functionality of [rfcbot][rfcbot] and are currently awaiting
+ signoff of all team members in order to enter the final comment period.
-* Dark blue, **beta-** labels track changes which need to be backported into
- the beta branches.
+* Pink, **regression**-prefixed labels track regressions from stable to the
+ release channels.
-* The purple **metabug** label marks lists of bugs collected by other
- categories.
+* The light orange **relnotes** label marks issues that should be documented in
+ the release notes of the next release.
+
+* Gray, **S**-prefixed labels are used for tracking the **status** of pull
+ requests.
+
+* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
+[rfcbot]: https://github.com/dikaiosune/rust-dashboard/blob/master/RFCBOT.md
## Out-of-tree Contributions
environment:
- SCCACHE_BUCKET: rust-lang-ci-sccache
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ SCCACHE_REGION: us-west-1
AWS_ACCESS_KEY_ID: AKIAJAMV3QAMMA6AXHFQ
AWS_SECRET_ACCESS_KEY:
secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80
+++ /dev/null
-
-fn foo(x: fn(&u8, &u8), y: Vec<&u8>, z: &u8) {
-// Debruijn 1 1 1 1
-// Anon-Index 0 1 0 1
-// ------
-// debruijn indices are shifted by 1 in here
- y.push(z); // index will be zero or one
-}
"alloc_system 0.0.0",
"build_helper 0.1.0",
"core 0.0.0",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
]
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "cmake"
-version = "0.1.24"
+version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.0.0"
dependencies = [
"core 0.0.0",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "error-chain"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "error-chain"
version = "0.11.0"
[[package]]
name = "gcc"
-version = "0.3.53"
+version = "0.3.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "handlebars"
-version = "0.26.2"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mdbook"
-version = "0.0.22"
+version = "0.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.9.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"core 0.0.0",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustfmt-nightly 0.2.5",
"serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-analysis"
-version = "0.6.5"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.0"
dependencies = [
"clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_bitflags 0.0.0",
]
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
version = "0.0.0"
dependencies = [
"flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
dependencies = [
"build_helper 0.1.0",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustfmt-nightly"
version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"collections 0.0.0",
"compiler_builtins 0.0.0",
"core 0.0.0",
- "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0"
-"checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f"
+"checksum cmake 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "0c8a6541a55bcd72d3de4faee2d101a5a66df29790282c7f797082a7228a9b3d"
"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299"
"checksum core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5909502e547762013619f4c4e01cc7393c20fe2d52d7fa471c1210adb2320dc7"
"checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
+"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866"
"checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3"
"checksum futures 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a82bdc62350ca9d7974c760e9665102fc9d740992a528c2254aa930e53b783c4"
-"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a"
+"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum git2 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1c0203d653f4140241da0c1375a404f0a397249ec818cd2076c6280c50f6fa"
"checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum globset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "feeb1b6840809ef5efcf7a4a990bc4e1b7ee3df8cf9e2379a75aeb2ba42ac9c3"
"checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4"
-"checksum handlebars 0.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fbba80e74e9591a5f6a4ffff6b7f9d645759a896e431cfbdc853e9184370294a"
+"checksum handlebars 0.27.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef7567daf271a32e60301e4821fcb5b51a5b535167115d1ce04f46c3f0a15f0b"
"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
"checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db"
"checksum html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5298d63081a642508fce965740ddb03a386c5d81bf1fef0579a815cf49cb8c68"
"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699"
"checksum markup5ever 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff834ac7123c6a37826747e5ca09db41fd7a83126792021c2e636ad174bb77d3"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "22911d86cde6f80fa9f0fb2a68bbbde85d97af4fe0ce267141c83a4187d28700"
+"checksum mdbook 0.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "146eadfc6d141452a364c351f07bb19208d1401e931f40b8532f87bba3ecc40f"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4"
"checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726"
"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db"
-"checksum rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cb40c0371765897ae428b5706bb17135705ad4f6d1b8b6afbaabcf8c9b5cff"
+"checksum rls-analysis 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4302cc8291570d7f817945845d8c01756e833dbc93c0a87d4f6c9a0b0b7992f1"
"checksum rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11d339f1888e33e74d8032de0f83c40b2bdaaaf04a8cfc03b32186c3481fb534"
"checksum rls-rustc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b21ea952e9bf1569929abf1bb920262cde04b7b1b26d8e0260286302807299d2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
-"checksum rustfmt-nightly 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7d6dbb39239e54df780a850721fba87b3fdb2e645b39041742ec111369cec6af"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
"checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
"tools/cargo",
"tools/rustdoc",
"tools/rls",
+ "tools/rustfmt",
# FIXME(https://github.com/rust-lang/cargo/issues/4089): move these to exclude
"tools/rls/test_data/borrow_error",
"tools/rls/test_data/completion",
debug = false
debug-assertions = false
-[patch.'https://github.com/rust-lang/cargo']
+[patch."https://github.com/rust-lang/cargo"]
cargo = { path = "tools/cargo" }
+
+# Override rustfmt dependencies both on the repo and the crate (the RLS
+# sometimes uses either).
+# FIXME should only need the crates.io patch, long term.
+[patch.'https://github.com/rust-lang-nursery/rustfmt']
+rustfmt-nightly = { path = "tools/rustfmt" }
+[patch.crates-io]
+rustfmt-nightly = { path = "tools/rustfmt" }
filetime = "0.1"
num_cpus = "1.0"
getopts = "0.2"
-gcc = "0.3.50"
+gcc = "0.3.54"
libc = "0.2"
serde = "1.0.8"
serde_derive = "1.0.8"
tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
- native::Llvm),
+ native::Llvm, tool::Rustfmt),
Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc,
check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs,
- check::ErrorIndex, check::Distcheck),
+ check::ErrorIndex, check::Distcheck, check::Rustfmt),
Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
}
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Rustfmt {
+ stage: u32,
+ host: Interned<String>,
+}
+
+impl Step for Rustfmt {
+ type Output = ();
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ run.path("src/tools/rustfmt")
+ }
+
+ fn make_run(run: RunConfig) {
+ run.builder.ensure(Rustfmt {
+ stage: run.builder.top_stage,
+ host: run.target,
+ });
+ }
+
+ /// Runs `cargo test` for rustfmt.
+ fn run(self, builder: &Builder) {
+ let build = builder.build;
+ let stage = self.stage;
+ let host = self.host;
+ let compiler = builder.compiler(stage, host);
+
+ builder.ensure(tool::Rustfmt { compiler, target: self.host });
+ let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
+ cargo.arg("--manifest-path").arg(build.src.join("src/tools/rustfmt/Cargo.toml"));
+
+ // Don't build tests dynamically, just a pain to work with
+ cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
+
+ builder.add_rustc_lib_path(compiler, &mut cargo);
+
+ try_run(build, &mut cargo);
+ }
+}
+
fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString {
// Configure PATH to find the right rustc. NB. we have to use PATH
// and not RUSTC because the Cargo test suite has tests that will
let compiler = builder.compiler(builder.top_stage, self.host);
let target = compiler.host;
- builder.ensure(RemoteCopyLibs { compiler, target });
-
- let mut cargo = builder.cargo(compiler, Mode::Librustc, target, test_kind.subcommand());
- compile::rustc_cargo(build, &compiler, target, &mut cargo);
+ let mut cargo = tool::prepare_tool_cargo(builder,
+ compiler,
+ target,
+ test_kind.subcommand(),
+ "src/tools/rustdoc");
let _folder = build.fold_output(|| {
format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
});
.arg("--output-dir").arg(&distdir(build))
.arg("--non-installed-overlay").arg(&overlay)
.arg(format!("--package-name={}-{}", name, target))
- .arg("--component-name=rls")
.arg("--legacy-manifest-dirs=rustlib,cargo");
+
+ if build.config.channel == "nightly" {
+ cmd.arg("--component-name=rls");
+ } else {
+ cmd.arg("--component-name=rls-preview");
+ }
+
build.run(&mut cmd);
distdir(build).join(format!("{}-{}.tar.gz", name, target))
}
cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
.join(format!("rust-std-{}", target)),
&exe.join("rust-std"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target))
- .join("rls"),
- &exe.join("rls"));
+ let rls_path = if build.config.channel == "nightly" {
+ work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls")
+ } else {
+ work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview")
+ };
+ cp_r(&rls_path, &exe.join("rls"));
cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
.join(format!("rust-analysis-{}", target)),
&exe.join("rust-analysis"));
src/tools/cargotest \
src/tools/cargo \
src/tools/rls \
+ src/tools/rustfmt \
src/test/pretty \
src/test/run-pass/pretty \
src/test/run-fail/pretty \
drop(fs::remove_dir_all(&dst));
build.run(Command::new("tar").arg("xf").arg(&tarball).current_dir(&out));
- let mut configure = Command::new(obj.join("Configure"));
+ let mut configure = Command::new("perl");
+ configure.arg(obj.join("Configure"));
configure.arg(format!("--prefix={}", dst.display()));
configure.arg("no-dso");
configure.arg("no-ssl2");
let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
- let mut cargo = prepare_tool_cargo(builder, compiler, target, path);
+ let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
build.run(&mut cargo);
build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
}
}
-fn prepare_tool_cargo(
+pub fn prepare_tool_cargo(
builder: &Builder,
compiler: Compiler,
target: Interned<String>,
+ command: &'static str,
path: &'static str,
) -> Command {
let build = builder.build;
- let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
+ let mut cargo = builder.cargo(compiler, Mode::Tool, target, command);
let dir = build.src.join(path);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
impl<'a> Builder<'a> {
pub fn tool_exe(&self, tool: Tool) -> PathBuf {
+ let stage = self.tool_default_stage(tool);
match tool {
$(Tool::$name =>
self.ensure($name {
- compiler: self.compiler(0, self.build.build),
+ compiler: self.compiler(stage, self.build.build),
target: self.build.build,
}),
)+
}
}
+
+ pub fn tool_default_stage(&self, tool: Tool) -> u32 {
+ // Compile the error-index in the top stage as it depends on
+ // rustdoc, so we want to avoid recompiling rustdoc twice if we
+ // can. Otherwise compile everything else in stage0 as there's
+ // no need to rebootstrap everything
+ match tool {
+ Tool::ErrorIndex => self.top_stage,
+ _ => 0,
+ }
+ }
}
$(
let mut cargo = prepare_tool_cargo(builder,
build_compiler,
target,
+ "build",
"src/tools/rustdoc");
build.run(&mut cargo);
// Cargo adds a number of paths to the dylib search path on windows, which results in
}
}
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct Rustfmt {
+ pub compiler: Compiler,
+ pub target: Interned<String>,
+}
+
+impl Step for Rustfmt {
+ type Output = PathBuf;
+ const DEFAULT: bool = true;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ let builder = run.builder;
+ run.path("src/tools/rustfmt").default_condition(builder.build.config.extended)
+ }
+
+ fn make_run(run: RunConfig) {
+ run.builder.ensure(Rustfmt {
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ target: run.target,
+ });
+ }
+
+ fn run(self, builder: &Builder) -> PathBuf {
+ builder.ensure(ToolBuild {
+ compiler: self.compiler,
+ target: self.target,
+ tool: "rustfmt",
+ mode: Mode::Librustc,
+ path: "src/tools/rustfmt",
+ })
+ }
+}
+
impl<'a> Builder<'a> {
/// Get a `Command` which is ready to run `tool` in `stage` built for
/// `host`.
pub fn tool_cmd(&self, tool: Tool) -> Command {
let mut cmd = Command::new(self.tool_exe(tool));
- let compiler = self.compiler(0, self.build.build);
+ let compiler = self.compiler(self.tool_default_stage(tool), self.build.build);
self.prepare_tool_cmd(compiler, &mut cmd);
cmd
}
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ autoconf \
+ automake \
+ bison \
+ bzip2 \
+ ca-certificates \
+ cmake \
+ curl \
+ file \
+ flex \
+ g++ \
+ gawk \
+ git \
+ libcurl4-openssl-dev \
+ libssl-dev \
+ make \
+ nasm \
+ pkg-config \
+ python2.7 \
+ sudo \
+ texinfo \
+ wget \
+ xz-utils \
+ zlib1g-dev
+
+COPY dist-x86_64-haiku/llvm-config.sh /bin/llvm-config-haiku
+
+ENV ARCH=x86_64
+
+WORKDIR /tmp
+COPY dist-x86_64-haiku/build-toolchain.sh /tmp/
+RUN /tmp/build-toolchain.sh $ARCH
+
+COPY dist-x86_64-haiku/fetch-packages.sh /tmp/
+RUN /tmp/fetch-packages.sh
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV HOST=x86_64-unknown-haiku
+ENV TARGET=target.$HOST
+
+ENV RUST_CONFIGURE_ARGS --host=$HOST --target=$HOST --disable-jemalloc \
+ --set=$TARGET.cc=x86_64-unknown-haiku-gcc \
+ --set=$TARGET.cxx=x86_64-unknown-haiku-g++ \
+ --set=$TARGET.llvm-config=/bin/llvm-config-haiku
+ENV SCRIPT python2.7 ../x.py dist
--- /dev/null
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+ARCH=$1
+
+TOP=$(pwd)
+
+BUILDTOOLS=$TOP/buildtools
+HAIKU=$TOP/haiku
+OUTPUT=/tools
+SYSROOT=$OUTPUT/cross-tools-$ARCH/sysroot
+PACKAGE_ROOT=/system
+
+hide_output() {
+ set +x
+ on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+ trap "$on_err" ERR
+ bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+ PING_LOOP_PID=$!
+ $@ &> /tmp/build.log
+ trap - ERR
+ kill $PING_LOOP_PID
+ set -x
+}
+
+# First up, build a cross-compiler
+git clone --depth=1 https://git.haiku-os.org/haiku
+git clone --depth=1 https://git.haiku-os.org/buildtools
+cd $BUILDTOOLS/jam
+hide_output make
+hide_output ./jam0 install
+mkdir -p $OUTPUT
+cd $OUTPUT
+hide_output $HAIKU/configure --build-cross-tools $ARCH $TOP/buildtools
+
+# Set up sysroot to redirect to /system
+mkdir -p $SYSROOT/boot
+mkdir -p $PACKAGE_ROOT
+ln -s $PACKAGE_ROOT $SYSROOT/boot/system
+
+# Build needed packages and tools for the cross-compiler
+hide_output jam -q haiku.hpkg haiku_devel.hpkg '<build>package'
+
+# Set up our sysroot
+cp $OUTPUT/objects/linux/lib/*.so /lib/x86_64-linux-gnu
+cp $OUTPUT/objects/linux/x86_64/release/tools/package/package /bin/
+find $SYSROOT/../bin/ -type f -exec ln -s {} /bin/ \;
+
+# Extract packages
+package extract -C $PACKAGE_ROOT $OUTPUT/objects/haiku/$ARCH/packaging/packages/haiku.hpkg
+package extract -C $PACKAGE_ROOT $OUTPUT/objects/haiku/$ARCH/packaging/packages/haiku_devel.hpkg
+find $OUTPUT/download/ -name '*.hpkg' -exec package extract -C $PACKAGE_ROOT {} \;
+
+# Fix libgcc_s so we can link to it
+cd $PACKAGE_ROOT/develop/lib
+ln -s ../../lib/libgcc_s.so libgcc_s.so
+
+# Clean up
+rm -rf $BUILDTOOLS $HAIKU $OUTPUT/Jamfile $OUTPUT/attributes $OUTPUT/build \
+ $OUTPUT/build_packages $OUTPUT/download $OUTPUT/objects
--- /dev/null
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+wget http://packages.haiku-os.org/haikuports/master/hpkg/llvm-4.0.1-2-x86_64.hpkg
+wget http://packages.haiku-os.org/haikuports/master/hpkg/llvm_libs-4.0.1-2-x86_64.hpkg
+
+package extract -C /system llvm-4.0.1-2-x86_64.hpkg
+package extract -C /system llvm_libs-4.0.1-2-x86_64.hpkg
+
+rm -f *.hpkg
--- /dev/null
+#!/bin/sh
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+case $1 in
+--version) echo 4.0.1;;
+--prefix) echo $SCRATCH/haiku-cross/sysroot/boot/system;;
+--bindir) echo $SCRATCH/haiku-cross/sysroot/boot/system/bin;;
+--includedir) echo $SCRATCH/haiku-cross/sysroot/boot/system/develop/headers;;
+--libdir) echo $SCRATCH/haiku-/cross/sysroot/boot/system/develop/lib;;
+--cmakedir) echo $SCRATCH/haiku-/cross/sysroot/boot/system/develop/lib/cmake/llvm;;
+--cppflags) echo -I$SCRATCH/haiku-/cross/sysroot/boot/system/develop/headers \
+ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS;;
+--cflags) echo -I$SCRATCH/haiku-cross/sysroot/boot/system/develop/headers \
+ -fPIC -Wall -W -Wno-unused-parameter -Wwrite-strings \
+ -Wno-missing-field-initializers -pedantic -Wno-long-long -Wno-comment \
+ -Werror=date-time -ffunction-sections -fdata-sections -O3 -DNDEBUG \
+ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS;;
+--cxxflags) echo -I/$SCRATCH/haiku-cross/sysroot/boot/system/develop/headers \
+ -fPIC -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter \
+ -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic \
+ -Wno-long-long -Wno-maybe-uninitialized -Wdelete-non-virtual-dtor \
+ -Wno-comment -Werror=date-time -std=c++11 -ffunction-sections \
+ -fdata-sections -O3 -DNDEBUG -fno-exceptions \
+ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS;;
+--ldflags) echo -L$SCRATCH/haiku-cross/sysroot/boot/system/develop/lib ;;
+--system-libs) echo ;;
+--libs) echo -lLLVM-4.0;;
+--libfiles) echo $SCRATCH/haiku-cross/sysroot/boot/system/develop/lib/libLLVM-4.0.so;;
+--components) echo aarch64 aarch64asmparser aarch64asmprinter aarch64codegen \
+ aarch64desc aarch64disassembler aarch64info aarch64utils all \
+ all-targets amdgpu amdgpuasmparser amdgpuasmprinter amdgpucodegen \
+ amdgpudesc amdgpudisassembler amdgpuinfo amdgpuutils analysis arm \
+ armasmparser armasmprinter armcodegen armdesc armdisassembler \
+ arminfo asmparser asmprinter bitreader bitwriter bpf bpfasmprinter \
+ bpfcodegen bpfdesc bpfdisassembler bpfinfo codegen core coroutines \
+ coverage debuginfocodeview debuginfodwarf debuginfomsf debuginfopdb \
+ demangle engine executionengine globalisel hexagon hexagonasmparser \
+ hexagoncodegen hexagondesc hexagondisassembler hexagoninfo \
+ instcombine instrumentation interpreter ipo irreader lanai \
+ lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo \
+ lanaiinstprinter libdriver lineeditor linker lto mc mcdisassembler \
+ mcjit mcparser mips mipsasmparser mipsasmprinter mipscodegen \
+ mipsdesc mipsdisassembler mipsinfo mirparser msp430 msp430asmprinter \
+ msp430codegen msp430desc msp430info native nativecodegen nvptx \
+ nvptxasmprinter nvptxcodegen nvptxdesc nvptxinfo objcarcopts object \
+ objectyaml option orcjit passes powerpc powerpcasmparser \
+ powerpcasmprinter powerpccodegen powerpcdesc powerpcdisassembler \
+ powerpcinfo profiledata riscv riscvcodegen riscvdesc riscvinfo \
+ runtimedyld scalaropts selectiondag sparc sparcasmparser \
+ sparcasmprinter sparccodegen sparcdesc sparcdisassembler sparcinfo \
+ support symbolize systemz systemzasmparser systemzasmprinter \
+ systemzcodegen systemzdesc systemzdisassembler systemzinfo tablegen \
+ target transformutils vectorize x86 x86asmparser x86asmprinter \
+ x86codegen x86desc x86disassembler x86info x86utils xcore \
+ xcoreasmprinter xcorecodegen xcoredesc xcoredisassembler xcoreinfo;;
+--host-target) echo x86_64-unknown-haiku;;
+--has-rtti) echo YES;;
+--shared-mode) echo shared;;
+esac
args=
if [ "$SCCACHE_BUCKET" != "" ]; then
- args="$args --env SCCACHE_BUCKET=$SCCACHE_BUCKET"
- args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
- args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
+ args="$args --env SCCACHE_BUCKET"
+ args="$args --env SCCACHE_REGION"
+ args="$args --env AWS_ACCESS_KEY_ID"
+ args="$args --env AWS_SECRET_ACCESS_KEY"
args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log"
args="$args --volume $objdir/tmp:/tmp/sccache"
else
--env SRC=/checkout \
$args \
--env CARGO_HOME=/cargo \
- --env DEPLOY=$DEPLOY \
- --env DEPLOY_ALT=$DEPLOY_ALT \
+ --env DEPLOY \
+ --env DEPLOY_ALT \
--env LOCAL_USER_ID=`id -u` \
- --env TRAVIS=${TRAVIS-false} \
+ --env TRAVIS \
--env TRAVIS_BRANCH \
--volume "$HOME/.cargo:/cargo" \
--volume "$HOME/rustsrc:$HOME/rustsrc" \
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
fi
else
- RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
+ # We almost always want debug assertions enabled, but sometimes this takes too
+ # long for too little benefit, so we just turn them off.
+ if [ "$NO_DEBUG_ASSERTIONS" = "" ]; then
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
+ fi
# In general we always want to run tests with LLVM assertions enabled, but not
# all platforms currently support that, so we have an option to disable.
The basic idea is this:
-```rust,ignore
+```ignore
/// # Examples
///
/// ```
The triple backticks start and end code blocks. If this were in a file named `foo.rs`,
running `rustdoc --test foo.rs` will extract this example, and then run it as a test.
+Please note that by default, if no language is set for the block code, `rustdoc`
+assumes it is `Rust` code. So the following:
+
+```rust
+let x = 5;
+```
+
+is strictly equivalent to:
+
+```
+let x = 5;
+```
+
There's some subtlety though! Read on for more details.
## Pre-processing examples
```text
First, we set `x` to five:
- ```rust
+ ```
let x = 5;
# let y = 6;
# println!("{}", x + y);
Next, we set `y` to six:
- ```rust
+ ```
# let x = 5;
let y = 6;
# println!("{}", x + y);
Finally, we print the sum of `x` and `y`:
- ```rust
+ ```
# let x = 5;
# let y = 6;
println!("{}", x + y);
Another case where the use of `#` is handy is when you want to ignore
error handling. Lets say you want the following,
-```rust,ignore
+```ignore
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
The problem is that `?` returns a `Result<T, E>` and test functions
don't return anything so this will give a mismatched types error.
-```rust,ignore
+```ignore
/// A doc test using ?
///
/// ```
/// # }
/// ```
///
-/// ```rust,should_panic
+/// ```should_panic
/// # #[macro_use] extern crate foo;
/// # fn main() {
/// panic_unless!(true == false, “I’m broken.”);
`should_panic` tells `rustdoc` that the code should compile correctly, but
not actually pass as a test.
-```rust
+```text
/// ```no_run
/// loop {
/// println!("Hello, world");
# fn foo() {}
```
+`compile_fail` tells `rustdoc` that the compilation should fail. If it
+compiles, then the test will fail. However please note that code failing
+with the current Rust release may work in a future release, as new features
+are added.
+
+```text
+/// ```compile_fail
+/// let x = 5;
+/// x += 2; // shouldn't compile!
+/// ```
+```
+
The `no_run` attribute will compile your code, but not run it. This is
important for examples such as "Here's how to retrieve a web page,"
which you would want to ensure compiles, but might be run in a test
use core::fmt;
use core::cmp::Ordering;
use core::intrinsics::abort;
-use core::mem::{self, size_of_val, uninitialized};
+use core::mem::{self, align_of_val, size_of_val, uninitialized};
use core::ops::Deref;
use core::ops::CoerceUnsized;
use core::ptr::{self, Shared};
Ok(elem)
}
}
+}
+impl<T: ?Sized> Arc<T> {
/// Consumes the `Arc`, returning the wrapped pointer.
///
/// To avoid a memory leak the pointer must be converted back to an `Arc` using
/// ```
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
- // To find the corresponding pointer to the `ArcInner` we need to subtract the offset of the
- // `data` field from the pointer.
- let ptr = (ptr as *const u8).offset(-offset_of!(ArcInner<T>, data));
+ // Align the unsized value to the end of the ArcInner.
+ // Because it is ?Sized, it will always be the last field in memory.
+ let align = align_of_val(&*ptr);
+ let layout = Layout::new::<ArcInner<()>>();
+ let offset = (layout.size() + layout.padding_needed_for(align)) as isize;
+
+ // Reverse the offset to find the original ArcInner.
+ let fake_ptr = ptr as *mut ArcInner<T>;
+ let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
+
Arc {
- ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _),
+ ptr: Shared::new_unchecked(arc_ptr),
}
}
-}
-impl<T: ?Sized> Arc<T> {
/// Creates a new [`Weak`][weak] pointer to this value.
///
/// [weak]: struct.Weak.html
}
}
+ #[test]
+ fn test_into_from_raw_unsized() {
+ use std::fmt::Display;
+ use std::string::ToString;
+
+ let arc: Arc<str> = Arc::from("foo");
+
+ let ptr = Arc::into_raw(arc.clone());
+ let arc2 = unsafe { Arc::from_raw(ptr) };
+
+ assert_eq!(unsafe { &*ptr }, "foo");
+ assert_eq!(arc, arc2);
+
+ let arc: Arc<Display> = Arc::new(123);
+
+ let ptr = Arc::into_raw(arc.clone());
+ let arc2 = unsafe { Arc::from_raw(ptr) };
+
+ assert_eq!(unsafe { &*ptr }.to_string(), "123");
+ assert_eq!(arc2.to_string(), "123");
+ }
+
#[test]
fn test_cowarc_clone_make_mut() {
let mut cow0 = Arc::new(75);
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
- loop {
- match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
- Less => return self.a.next(),
- Equal => {
- self.b.next();
- return self.a.next();
- }
- Greater => return self.b.next(),
+ match cmp_opt(self.a.peek(), self.b.peek(), Greater, Less) {
+ Less => self.a.next(),
+ Equal => {
+ self.b.next();
+ self.a.next()
}
+ Greater => self.b.next(),
}
}
macro_rules! format {
($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*)))
}
-
-// Private macro to get the offset of a struct field in bytes from the address of the struct.
-macro_rules! offset_of {
- ($container:path, $field:ident) => {{
- // Make sure the field actually exists. This line ensures that a compile-time error is
- // generated if $field is accessed through a Deref impl.
- let $container { $field : _, .. };
-
- // Create an (invalid) instance of the container and calculate the offset to its
- // field. Using a null pointer might be UB if `&(*(0 as *const T)).field` is interpreted to
- // be nullptr deref.
- let invalid: $container = ::core::mem::uninitialized();
- let offset = &invalid.$field as *const _ as usize - &invalid as *const _ as usize;
-
- // Do not run destructors on the made up invalid instance.
- ::core::mem::forget(invalid);
- offset as isize
- }};
-}
#[cfg(test)]
use std::boxed::Box;
+use core::any::Any;
use core::borrow;
use core::cell::Cell;
use core::cmp::Ordering;
use core::intrinsics::abort;
use core::marker;
use core::marker::Unsize;
-use core::mem::{self, forget, size_of_val, uninitialized};
+use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
use core::ops::Deref;
use core::ops::CoerceUnsized;
use core::ptr::{self, Shared};
Err(this)
}
}
+}
+impl<T: ?Sized> Rc<T> {
/// Consumes the `Rc`, returning the wrapped pointer.
///
/// To avoid a memory leak the pointer must be converted back to an `Rc` using
/// ```
#[stable(feature = "rc_raw", since = "1.17.0")]
pub unsafe fn from_raw(ptr: *const T) -> Self {
- // To find the corresponding pointer to the `RcBox` we need to subtract the offset of the
- // `value` field from the pointer.
+ // Align the unsized value to the end of the RcBox.
+ // Because it is ?Sized, it will always be the last field in memory.
+ let align = align_of_val(&*ptr);
+ let layout = Layout::new::<RcBox<()>>();
+ let offset = (layout.size() + layout.padding_needed_for(align)) as isize;
+
+ // Reverse the offset to find the original RcBox.
+ let fake_ptr = ptr as *mut RcBox<T>;
+ let rc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset));
- let ptr = (ptr as *const u8).offset(-offset_of!(RcBox<T>, value));
Rc {
- ptr: Shared::new_unchecked(ptr as *mut u8 as *mut _)
+ ptr: Shared::new_unchecked(rc_ptr),
}
}
-}
-impl<T: ?Sized> Rc<T> {
/// Creates a new [`Weak`][weak] pointer to this value.
///
/// [weak]: struct.Weak.html
}
}
+impl Rc<Any> {
+ #[inline]
+ #[unstable(feature = "rc_downcast", issue = "44608")]
+ /// Attempt to downcast the `Rc<Any>` to a concrete type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(rc_downcast)]
+ /// use std::any::Any;
+ /// use std::rc::Rc;
+ ///
+ /// fn print_if_string(value: Rc<Any>) {
+ /// if let Ok(string) = value.downcast::<String>() {
+ /// println!("String ({}): {}", string.len(), string);
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let my_string = "Hello World".to_string();
+ /// print_if_string(Rc::new(my_string));
+ /// print_if_string(Rc::new(0i8));
+ /// }
+ /// ```
+ pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<Any>> {
+ if (*self).is::<T>() {
+ // avoid the pointer arithmetic in from_raw
+ unsafe {
+ let raw: *const RcBox<Any> = self.ptr.as_ptr();
+ forget(self);
+ Ok(Rc {
+ ptr: Shared::new_unchecked(raw as *const RcBox<T> as *mut _),
+ })
+ }
+ } else {
+ Err(self)
+ }
+ }
+}
+
impl<T: ?Sized> Rc<T> {
// Allocates an `RcBox<T>` with sufficient space for an unsized value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
}
}
+ #[test]
+ fn test_into_from_raw_unsized() {
+ use std::fmt::Display;
+ use std::string::ToString;
+
+ let rc: Rc<str> = Rc::from("foo");
+
+ let ptr = Rc::into_raw(rc.clone());
+ let rc2 = unsafe { Rc::from_raw(ptr) };
+
+ assert_eq!(unsafe { &*ptr }, "foo");
+ assert_eq!(rc, rc2);
+
+ let rc: Rc<Display> = Rc::new(123);
+
+ let ptr = Rc::into_raw(rc.clone());
+ let rc2 = unsafe { Rc::from_raw(ptr) };
+
+ assert_eq!(unsafe { &*ptr }.to_string(), "123");
+ assert_eq!(rc2.to_string(), "123");
+ }
+
#[test]
fn get_mut() {
let mut x = Rc::new(3);
assert_eq!(&r[..], [1, 2, 3]);
}
+
+ #[test]
+ fn test_downcast() {
+ use std::any::Any;
+
+ let r1: Rc<Any> = Rc::new(i32::max_value());
+ let r2: Rc<Any> = Rc::new("abc");
+
+ assert!(r1.clone().downcast::<u32>().is_err());
+
+ let r1i32 = r1.downcast::<i32>();
+ assert!(r1i32.is_ok());
+ assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value()));
+
+ assert!(r2.clone().downcast::<i32>().is_err());
+
+ let r2str = r2.downcast::<&'static str>();
+ assert!(r2str.is_ok());
+ assert_eq!(r2str.unwrap(), Rc::new("abc"));
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
/// Returns an iterator of `u16` over the string encoded as UTF-16.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "Zażółć gęślą jaźń";
+ ///
+ /// let utf8_len = text.len();
+ /// let utf16_len = text.encode_utf16().count();
+ ///
+ /// assert!(utf16_len <= utf8_len);
+ /// ```
#[stable(feature = "encode_utf16", since = "1.8.0")]
pub fn encode_utf16(&self) -> EncodeUtf16 {
EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) }
}
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "this is a string";
+ /// let boxed_str = s.to_owned().into_boxed_str();
+ /// let boxed_bytes = boxed_str.into_boxed_bytes();
+ /// assert_eq!(*boxed_bytes, *s.as_bytes());
+ /// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
self.into()
/// Converts a boxed slice of bytes to a boxed string slice without checking
/// that the string contains valid UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let smile_utf8 = Box::new([226, 152, 186]);
+/// let smile = unsafe { std::str::from_boxed_utf8_unchecked(smile_utf8) };
+///
+/// assert_eq!("☺", &*smile);
+/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
mem::transmute(v)
/// Decode a UTF-16 encoded slice `v` into a `String`, replacing
/// invalid data with the replacement character (U+FFFD).
///
+ /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`],
+ /// `from_utf16_lossy` returns a `String` since the UTF-16 to UTF-8
+ /// conversion requires a memory allocation.
+ ///
+ /// [`from_utf8_lossy`]: #method.from_utf8_lossy
+ /// [`Cow<'a, str>`]: ../borrow/enum.Cow.html
+ ///
/// # Examples
///
/// Basic usage:
self
}
- /// Extracts a string slice containing the entire string.
+ /// Converts a `String` into a mutable string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// use std::ascii::AsciiExt;
+ ///
+ /// let mut s = String::from("foobar");
+ /// let s_mut_str = s.as_mut_str();
+ ///
+ /// s_mut_str.make_ascii_uppercase();
+ ///
+ /// assert_eq!("FOOBAR", s_mut_str);
+ /// ```
#[inline]
#[stable(feature = "string_as_str", since = "1.7.0")]
pub fn as_mut_str(&mut self) -> &mut str {
///
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
/// (at least, it's highly likely to be incorrect if it wasn't).
+ /// * `ptr`'s `T` needs to have the same size and alignment as it was allocated with.
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the capacity that the pointer was allocated with.
///
/// Using this method is equivalent to the following code:
///
/// ```
- /// # let some_predicate = |x: &mut i32| { *x == 2 };
- /// # let mut vec = vec![1, 2, 3, 4, 5];
+ /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 };
+ /// # let mut vec = vec![1, 2, 3, 4, 5, 6];
/// let mut i = 0;
/// while i != vec.len() {
/// if some_predicate(&mut vec[i]) {
/// let val = vec.remove(i);
/// // your code here
+ /// } else {
+ /// i += 1;
/// }
- /// i += 1;
/// }
+ ///
+ /// # assert_eq!(vec, vec![1, 4, 5]);
/// ```
///
/// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
-Subproject commit 38ffaf97aa418cc369ca0197a72a0b927cc0f622
+Subproject commit ef4951582f620c589cd9e18ec182538bf116bce3
acc
});
}
+
+#[bench]
+fn bench_flat_map_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 {
+ (0i64..1000).flat_map(|x| x..x+1000)
+ .map(black_box)
+ .sum()
+ });
+}
+
+#[bench]
+fn bench_flat_map_ref_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 {
+ (0i64..1000).flat_map(|x| x..x+1000)
+ .map(black_box)
+ .by_ref()
+ .sum()
+ });
+}
+
+#[bench]
+fn bench_flat_map_chain_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 {
+ (0i64..1000000).flat_map(|x| once(x).chain(once(x)))
+ .map(black_box)
+ .sum()
+ });
+}
+
+#[bench]
+fn bench_flat_map_chain_ref_sum(b: &mut Bencher) {
+ b.iter(|| -> i64 {
+ (0i64..1000000).flat_map(|x| once(x).chain(once(x)))
+ .map(black_box)
+ .by_ref()
+ .sum()
+ });
+}
/// let c = Cell::new(5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_cell_new"))]
#[inline]
pub const fn new(value: T) -> Cell<T> {
Cell {
/// let c = RefCell::new(5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_refcell_new"))]
#[inline]
pub const fn new(value: T) -> RefCell<T> {
RefCell {
/// let uc = UnsafeCell::new(5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_unsafe_cell_new"))]
#[inline]
pub const fn new(value: T) -> UnsafeCell<T> {
UnsafeCell { value: value }
/// # Examples
///
/// ```
- /// #![feature(ord_max_min)]
- ///
/// assert_eq!(2, 1.max(2));
/// assert_eq!(2, 2.max(2));
/// ```
- #[unstable(feature = "ord_max_min", issue = "25663")]
+ #[stable(feature = "ord_max_min", since = "1.22.0")]
fn max(self, other: Self) -> Self
where Self: Sized {
if other >= self { other } else { self }
/// # Examples
///
/// ```
- /// #![feature(ord_max_min)]
- ///
/// assert_eq!(1, 1.min(2));
/// assert_eq!(2, 2.min(2));
/// ```
- #[unstable(feature = "ord_max_min", issue = "25663")]
+ #[stable(feature = "ord_max_min", since = "1.22.0")]
fn min(self, other: Self) -> Self
where Self: Sized {
if self <= other { self } else { other }
/// // The no-copy, unsafe way, still using transmute, but not UB.
/// // This is equivalent to the original, but safer, and reuses the
/// // same Vec internals. Therefore the new inner type must have the
- /// // exact same size, and the same or lesser alignment, as the old
- /// // type. The same caveats exist for this method as transmute, for
+ /// // exact same size, and the same alignment, as the old type.
+ /// // The same caveats exist for this method as transmute, for
/// // the original inner type (`&i32`) to the converted inner type
/// // (`Option<&i32>`), so read the nomicon pages linked above.
/// let v_from_raw = unsafe {
- /// Vec::from_raw_parts(v_orig.as_mut_ptr(),
+ /// Vec::from_raw_parts(v_orig.as_mut_ptr() as *mut Option<&i32>,
/// v_orig.len(),
/// v_orig.capacity())
/// };
_ => (lo, None)
}
}
+
+ #[inline]
+ fn fold<Acc, Fold>(self, init: Acc, mut fold: Fold) -> Acc
+ where Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.frontiter.into_iter()
+ .chain(self.iter.map(self.f).map(U::into_iter))
+ .chain(self.backiter)
+ .fold(init, |acc, iter| iter.fold(acc, &mut fold))
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
#![feature(prelude_import)]
#![feature(repr_simd, platform_intrinsics)]
#![feature(rustc_attrs)]
+#![cfg_attr(not(stage0), feature(rustc_const_unstable))]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
+#![cfg_attr(not(stage0), feature(const_min_value))]
+#![cfg_attr(not(stage0), feature(const_max_value))]
+#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_isize_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_usize_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_i8_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_u8_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_i16_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_u16_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_i32_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_u32_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_i64_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_u64_new))]
+#![cfg_attr(not(stage0), feature(const_unsafe_cell_new))]
+#![cfg_attr(not(stage0), feature(const_cell_new))]
+#![cfg_attr(not(stage0), feature(const_nonzero_new))]
+
#[prelude_import]
#[allow(unused)]
use prelude::v1::*;
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_size_of"))]
pub const fn size_of<T>() -> usize {
unsafe { intrinsics::size_of::<T>() }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_align_of"))]
pub const fn align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
/// Opaque type representing the discriminant of an enum.
///
/// See the `discriminant` function in this module for more information.
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
pub struct Discriminant<T>(u64, PhantomData<*const T>);
// N.B. These trait implementations cannot be derived because we don't want any bounds on T.
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> Copy for Discriminant<T> {}
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> clone::Clone for Discriminant<T> {
fn clone(&self) -> Self {
*self
}
}
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> cmp::PartialEq for Discriminant<T> {
fn eq(&self, rhs: &Self) -> bool {
self.0 == rhs.0
}
}
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> cmp::Eq for Discriminant<T> {}
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> hash::Hash for Discriminant<T> {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
impl<T> fmt::Debug for Discriminant<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_tuple("Discriminant")
/// assert!(mem::discriminant(&Foo::B(1)) == mem::discriminant(&Foo::B(2)));
/// assert!(mem::discriminant(&Foo::B(3)) != mem::discriminant(&Foo::C(3)));
/// ```
-#[stable(feature = "discriminant_value", since = "1.22.0")]
+#[stable(feature = "discriminant_value", since = "1.21.0")]
pub fn discriminant<T>(v: &T) -> Discriminant<T> {
unsafe {
Discriminant(intrinsics::discriminant_value(v), PhantomData)
impl<T: Zeroable> NonZero<T> {
/// Creates an instance of NonZero with the provided value.
/// You must indeed ensure that the value is actually "non-zero".
+ #[unstable(feature = "nonzero",
+ reason = "needs an RFC to flesh out the design",
+ issue = "27730")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_nonzero_new"))]
#[inline]
pub const unsafe fn new_unchecked(inner: T) -> Self {
NonZero(inner)
/// assert_eq!(i8::min_value(), -128);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_min_value"))]
#[inline]
pub const fn min_value() -> Self {
!0 ^ ((!0 as $UnsignedT) >> 1) as Self
/// assert_eq!(i8::max_value(), 127);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_max_value"))]
#[inline]
pub const fn max_value() -> Self {
!Self::min_value()
/// assert_eq!(u8::min_value(), 0);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_min_value"))]
#[inline]
pub const fn min_value() -> Self { 0 }
/// assert_eq!(u8::max_value(), 255);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_max_value"))]
#[inline]
pub const fn max_value() -> Self { !0 }
/// as the compiler doesn't need to prove that it's sound to elide the
/// copy.
///
-/// # Undefined Behavior
+/// # Safety
///
/// This has all the same safety problems as `ptr::read` with respect to
/// invalid pointers, types, and double drops.
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_ptr_null"))]
pub const fn null<T>() -> *const T { 0 as *const T }
/// Creates a null mutable raw pointer.
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_ptr_null_mut"))]
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
/// Swaps the values at two mutable locations of the same type, without
}
}
- /// Calculates the offset from a pointer. `count` is in units of T; e.g. a
- /// `count` of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
+ /// Calculates the offset from a pointer.
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
///
/// # Safety
///
- /// Both the starting and resulting pointer must be either in bounds or one
- /// byte past the end of an allocated object. If either pointer is out of
- /// bounds or arithmetic overflow occurs then
- /// any further use of the returned value will result in undefined behavior.
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset, **in bytes**, cannot overflow or underflow an
+ /// `isize`.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().offset(vec.len() as isize)` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
///
/// # Examples
///
}
/// Calculates the offset from a pointer using wrapping arithmetic.
+ ///
/// `count` is in units of T; e.g. a `count` of 3 represents a pointer
/// offset of `3 * size_of::<T>()` bytes.
///
Some(diff / size as isize)
}
}
+
+ /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset, **in bytes**, cannot overflow or underflow an
+ /// `isize`.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum must fit in a `usize`.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().add(vec.len())` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let s: &str = "123";
+ /// let ptr: *const u8 = s.as_ptr();
+ ///
+ /// unsafe {
+ /// println!("{}", *ptr.add(1) as char);
+ /// println!("{}", *ptr.add(2) as char);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn add(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.offset(count as isize)
+ }
+
+ /// Calculates the offset from a pointer (convenience for
+ /// `.offset((count as isize).wrapping_neg())`).
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset cannot exceed `isize::MAX` **bytes**.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum must fit in a usize.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let s: &str = "123";
+ ///
+ /// unsafe {
+ /// let end: *const u8 = s.as_ptr().add(3);
+ /// println!("{}", *end.sub(1) as char);
+ /// println!("{}", *end.sub(2) as char);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn sub(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.offset((count as isize).wrapping_neg())
+ }
+
+ /// Calculates the offset from a pointer using wrapping arithmetic.
+ /// (convenience for `.wrapping_offset(count as isize)`)
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// The resulting pointer does not need to be in bounds, but it is
+ /// potentially hazardous to dereference (which requires `unsafe`).
+ ///
+ /// Always use `.add(count)` instead when possible, because `add`
+ /// allows the compiler to optimize better.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// // Iterate using a raw pointer in increments of two elements
+ /// let data = [1u8, 2, 3, 4, 5];
+ /// let mut ptr: *const u8 = data.as_ptr();
+ /// let step = 2;
+ /// let end_rounded_up = ptr.wrapping_add(6);
+ ///
+ /// // This loop prints "1, 3, 5, "
+ /// while ptr != end_rounded_up {
+ /// unsafe {
+ /// print!("{}, ", *ptr);
+ /// }
+ /// ptr = ptr.wrapping_add(step);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub fn wrapping_add(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.wrapping_offset(count as isize)
+ }
+
+ /// Calculates the offset from a pointer using wrapping arithmetic.
+ /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`)
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// The resulting pointer does not need to be in bounds, but it is
+ /// potentially hazardous to dereference (which requires `unsafe`).
+ ///
+ /// Always use `.sub(count)` instead when possible, because `sub`
+ /// allows the compiler to optimize better.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// // Iterate using a raw pointer in increments of two elements (backwards)
+ /// let data = [1u8, 2, 3, 4, 5];
+ /// let mut ptr: *const u8 = data.as_ptr();
+ /// let start_rounded_down = ptr.wrapping_sub(2);
+ /// ptr = ptr.wrapping_add(4);
+ /// let step = 2;
+ /// // This loop prints "5, 3, 1, "
+ /// while ptr != start_rounded_down {
+ /// unsafe {
+ /// print!("{}, ", *ptr);
+ /// }
+ /// ptr = ptr.wrapping_sub(step);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub fn wrapping_sub(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.wrapping_offset((count as isize).wrapping_neg())
+ }
+
+ /// Reads the value from `self` without moving it. This leaves the
+ /// memory in `self` unchanged.
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `self` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// The pointer must be aligned; use `read_unaligned` if that is not the case.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read(self) -> T
+ where T: Sized,
+ {
+ read(self)
+ }
+
+ /// Performs a volatile read of the value from `self` without moving it. This
+ /// leaves the memory in `self` unchanged.
+ ///
+ /// Volatile operations are intended to act on I/O memory, and are guaranteed
+ /// to not be elided or reordered by the compiler across other volatile
+ /// operations.
+ ///
+ /// # Notes
+ ///
+ /// Rust does not currently have a rigorously and formally defined memory model,
+ /// so the precise semantics of what "volatile" means here is subject to change
+ /// over time. That being said, the semantics will almost always end up pretty
+ /// similar to [C11's definition of volatile][c11].
+ ///
+ /// The compiler shouldn't change the relative order or number of volatile
+ /// memory operations. However, volatile memory operations on zero-sized types
+ /// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops
+ /// and may be ignored.
+ ///
+ /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `self` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read_volatile(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read_volatile(self) -> T
+ where T: Sized,
+ {
+ read_volatile(self)
+ }
+
+ /// Reads the value from `self` without moving it. This leaves the
+ /// memory in `self` unchanged.
+ ///
+ /// Unlike `read`, the pointer may be unaligned.
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `self` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read_unaligned(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read_unaligned(self) -> T
+ where T: Sized,
+ {
+ read_unaligned(self)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+ /// and destination may overlap.
+ ///
+ /// NOTE: this has the *same* argument order as `ptr::copy`.
+ ///
+ /// This is semantically equivalent to C's `memmove`.
+ ///
+ /// # Safety
+ ///
+ /// Care must be taken with the ownership of `self` and `dest`.
+ /// This method semantically moves the values of `self` into `dest`.
+ /// However it does not drop the contents of `self`, or prevent the contents
+ /// of `dest` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// ptr.copy_to(dst.as_mut_ptr(), elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_to(self, dest: *mut T, count: usize)
+ where T: Sized,
+ {
+ copy(self, dest, count)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+ /// and destination may *not* overlap.
+ ///
+ /// NOTE: this has the *same* argument order as `ptr::copy_nonoverlapping`.
+ ///
+ /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
+ ///
+ /// # Safety
+ ///
+ /// Beyond requiring that the program must be allowed to access both regions
+ /// of memory, it is Undefined Behavior for source and destination to
+ /// overlap. Care must also be taken with the ownership of `self` and
+ /// `self`. This method semantically moves the values of `self` into `dest`.
+ /// However it does not drop the contents of `dest`, or prevent the contents
+ /// of `self` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// ptr.copy_to_nonoverlapping(dst.as_mut_ptr(), elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
+ where T: Sized,
+ {
+ copy_nonoverlapping(self, dest, count)
+ }
+
+
}
#[lang = "mut_ptr"]
}
}
- /// Calculates the offset from a pointer. `count` is in units of T; e.g. a
- /// `count` of 3 represents a pointer offset of `3 * size_of::<T>()` bytes.
+ /// Calculates the offset from a pointer.
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
///
/// # Safety
///
- /// The offset must be in-bounds of the object, or one-byte-past-the-end.
- /// Otherwise `offset` invokes Undefined Behavior, regardless of whether
- /// the pointer is used.
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset, **in bytes**, cannot overflow or underflow an
+ /// `isize`.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().offset(vec.len() as isize)` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
///
/// # Examples
///
Some(diff / size as isize)
}
}
-}
-
-// Equality for pointers
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialEq for *const T {
- #[inline]
- fn eq(&self, other: &*const T) -> bool { *self == *other }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Eq for *const T {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialEq for *mut T {
- #[inline]
- fn eq(&self, other: &*mut T) -> bool { *self == *other }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Eq for *mut T {}
-/// Compare raw pointers for equality.
-///
-/// This is the same as using the `==` operator, but less generic:
-/// the arguments have to be `*const T` raw pointers,
-/// not anything that implements `PartialEq`.
-///
-/// This can be used to compare `&T` references (which coerce to `*const T` implicitly)
-/// by their address rather than comparing the values they point to
-/// (which is what the `PartialEq for &T` implementation does).
-///
+ /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset, **in bytes**, cannot overflow or underflow an
+ /// `isize`.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum must fit in a `usize`.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().add(vec.len())` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let s: &str = "123";
+ /// let ptr: *const u8 = s.as_ptr();
+ ///
+ /// unsafe {
+ /// println!("{}", *ptr.add(1) as char);
+ /// println!("{}", *ptr.add(2) as char);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn add(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.offset(count as isize)
+ }
+
+ /// Calculates the offset from a pointer (convenience for
+ /// `.offset((count as isize).wrapping_neg())`).
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// If any of the following conditions are violated, the result is Undefined
+ /// Behavior:
+ ///
+ /// * Both the starting and resulting pointer must be either in bounds or one
+ /// byte past the end of an allocated object.
+ ///
+ /// * The computed offset cannot exceed `isize::MAX` **bytes**.
+ ///
+ /// * The offset being in bounds cannot rely on "wrapping around" the address
+ /// space. That is, the infinite-precision sum must fit in a usize.
+ ///
+ /// The compiler and standard library generally tries to ensure allocations
+ /// never reach a size where an offset is a concern. For instance, `Vec`
+ /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so
+ /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe.
+ ///
+ /// Most platforms fundamentally can't even construct such an allocation.
+ /// For instance, no known 64-bit platform can ever serve a request
+ /// for 2^63 bytes due to page-table limitations or splitting the address space.
+ /// However, some 32-bit and 16-bit platforms may successfully serve a request for
+ /// more than `isize::MAX` bytes with things like Physical Address
+ /// Extension. As such, memory acquired directly from allocators or memory
+ /// mapped files *may* be too large to handle with this function.
+ ///
+ /// Consider using `wrapping_offset` instead if these constraints are
+ /// difficult to satisfy. The only advantage of this method is that it
+ /// enables more aggressive compiler optimizations.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let s: &str = "123";
+ ///
+ /// unsafe {
+ /// let end: *const u8 = s.as_ptr().add(3);
+ /// println!("{}", *end.sub(1) as char);
+ /// println!("{}", *end.sub(2) as char);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn sub(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.offset((count as isize).wrapping_neg())
+ }
+
+ /// Calculates the offset from a pointer using wrapping arithmetic.
+ /// (convenience for `.wrapping_offset(count as isize)`)
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// The resulting pointer does not need to be in bounds, but it is
+ /// potentially hazardous to dereference (which requires `unsafe`).
+ ///
+ /// Always use `.add(count)` instead when possible, because `add`
+ /// allows the compiler to optimize better.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// // Iterate using a raw pointer in increments of two elements
+ /// let data = [1u8, 2, 3, 4, 5];
+ /// let mut ptr: *const u8 = data.as_ptr();
+ /// let step = 2;
+ /// let end_rounded_up = ptr.wrapping_add(6);
+ ///
+ /// // This loop prints "1, 3, 5, "
+ /// while ptr != end_rounded_up {
+ /// unsafe {
+ /// print!("{}, ", *ptr);
+ /// }
+ /// ptr = ptr.wrapping_add(step);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub fn wrapping_add(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.wrapping_offset(count as isize)
+ }
+
+ /// Calculates the offset from a pointer using wrapping arithmetic.
+ /// (convenience for `.wrapping_offset((count as isize).wrapping_sub())`)
+ ///
+ /// `count` is in units of T; e.g. a `count` of 3 represents a pointer
+ /// offset of `3 * size_of::<T>()` bytes.
+ ///
+ /// # Safety
+ ///
+ /// The resulting pointer does not need to be in bounds, but it is
+ /// potentially hazardous to dereference (which requires `unsafe`).
+ ///
+ /// Always use `.sub(count)` instead when possible, because `sub`
+ /// allows the compiler to optimize better.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// // Iterate using a raw pointer in increments of two elements (backwards)
+ /// let data = [1u8, 2, 3, 4, 5];
+ /// let mut ptr: *const u8 = data.as_ptr();
+ /// let start_rounded_down = ptr.wrapping_sub(2);
+ /// ptr = ptr.wrapping_add(4);
+ /// let step = 2;
+ /// // This loop prints "5, 3, 1, "
+ /// while ptr != start_rounded_down {
+ /// unsafe {
+ /// print!("{}, ", *ptr);
+ /// }
+ /// ptr = ptr.wrapping_sub(step);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub fn wrapping_sub(self, count: usize) -> Self
+ where T: Sized,
+ {
+ self.wrapping_offset((count as isize).wrapping_neg())
+ }
+
+ /// Reads the value from `self` without moving it. This leaves the
+ /// memory in `self` unchanged.
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `self` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// The pointer must be aligned; use `read_unaligned` if that is not the case.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read(self) -> T
+ where T: Sized,
+ {
+ read(self)
+ }
+
+ /// Performs a volatile read of the value from `self` without moving it. This
+ /// leaves the memory in `self` unchanged.
+ ///
+ /// Volatile operations are intended to act on I/O memory, and are guaranteed
+ /// to not be elided or reordered by the compiler across other volatile
+ /// operations.
+ ///
+ /// # Notes
+ ///
+ /// Rust does not currently have a rigorously and formally defined memory model,
+ /// so the precise semantics of what "volatile" means here is subject to change
+ /// over time. That being said, the semantics will almost always end up pretty
+ /// similar to [C11's definition of volatile][c11].
+ ///
+ /// The compiler shouldn't change the relative order or number of volatile
+ /// memory operations. However, volatile memory operations on zero-sized types
+ /// (e.g. if a zero-sized type is passed to `read_volatile`) are no-ops
+ /// and may be ignored.
+ ///
+ /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `src` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read_volatile(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read_volatile(self) -> T
+ where T: Sized,
+ {
+ read_volatile(self)
+ }
+
+ /// Reads the value from `self` without moving it. This leaves the
+ /// memory in `self` unchanged.
+ ///
+ /// Unlike `read`, the pointer may be unaligned.
+ ///
+ /// # Safety
+ ///
+ /// Beyond accepting a raw pointer, this is unsafe because it semantically
+ /// moves the value out of `self` without preventing further usage of `self`.
+ /// If `T` is not `Copy`, then care must be taken to ensure that the value at
+ /// `self` is not used before the data is overwritten again (e.g. with `write`,
+ /// `zero_memory`, or `copy_memory`). Note that `*self = foo` counts as a use
+ /// because it will attempt to drop the value previously at `*self`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let x = 12;
+ /// let y = &x as *const i32;
+ ///
+ /// unsafe {
+ /// assert_eq!(y.read_unaligned(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn read_unaligned(self) -> T
+ where T: Sized,
+ {
+ read_unaligned(self)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+ /// and destination may overlap.
+ ///
+ /// NOTE: this has the *same* argument order as `ptr::copy`.
+ ///
+ /// This is semantically equivalent to C's `memmove`.
+ ///
+ /// # Safety
+ ///
+ /// Care must be taken with the ownership of `self` and `dest`.
+ /// This method semantically moves the values of `self` into `dest`.
+ /// However it does not drop the contents of `self`, or prevent the contents
+ /// of `dest` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// ptr.copy_to(dst.as_mut_ptr(), elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_to(self, dest: *mut T, count: usize)
+ where T: Sized,
+ {
+ copy(self, dest, count)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `self` to `dest`. The source
+ /// and destination may *not* overlap.
+ ///
+ /// NOTE: this has the *same* argument order as `ptr::copy_nonoverlapping`.
+ ///
+ /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
+ ///
+ /// # Safety
+ ///
+ /// Beyond requiring that the program must be allowed to access both regions
+ /// of memory, it is Undefined Behavior for source and destination to
+ /// overlap. Care must also be taken with the ownership of `self` and
+ /// `self`. This method semantically moves the values of `self` into `dest`.
+ /// However it does not drop the contents of `dest`, or prevent the contents
+ /// of `self` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// ptr.copy_to_nonoverlapping(dst.as_mut_ptr(), elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
+ where T: Sized,
+ {
+ copy_nonoverlapping(self, dest, count)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+ /// and destination may overlap.
+ ///
+ /// NOTE: this has the *opposite* argument order of `ptr::copy`.
+ ///
+ /// This is semantically equivalent to C's `memmove`.
+ ///
+ /// # Safety
+ ///
+ /// Care must be taken with the ownership of `src` and `self`.
+ /// This method semantically moves the values of `src` into `self`.
+ /// However it does not drop the contents of `self`, or prevent the contents
+ /// of `src` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// dst.as_mut_ptr().copy_from(ptr, elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_from(self, src: *const T, count: usize)
+ where T: Sized,
+ {
+ copy(src, self, count)
+ }
+
+ /// Copies `count * size_of<T>` bytes from `src` to `self`. The source
+ /// and destination may *not* overlap.
+ ///
+ /// NOTE: this has the *opposite* argument order of `ptr::copy_nonoverlapping`.
+ ///
+ /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
+ ///
+ /// # Safety
+ ///
+ /// Beyond requiring that the program must be allowed to access both regions
+ /// of memory, it is Undefined Behavior for source and destination to
+ /// overlap. Care must also be taken with the ownership of `src` and
+ /// `self`. This method semantically moves the values of `src` into `self`.
+ /// However it does not drop the contents of `self`, or prevent the contents
+ /// of `src` from being dropped or used.
+ ///
+ /// # Examples
+ ///
+ /// Efficiently create a Rust vector from an unsafe buffer:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// # #[allow(dead_code)]
+ /// unsafe fn from_buf_raw<T: Copy>(ptr: *const T, elts: usize) -> Vec<T> {
+ /// let mut dst = Vec::with_capacity(elts);
+ /// dst.set_len(elts);
+ /// dst.as_mut_ptr().copy_from_nonoverlapping(ptr, elts);
+ /// dst
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
+ where T: Sized,
+ {
+ copy_nonoverlapping(src, self, count)
+ }
+
+ /// Executes the destructor (if any) of the pointed-to value.
+ ///
+ /// This has two use cases:
+ ///
+ /// * It is *required* to use `drop_in_place` to drop unsized types like
+ /// trait objects, because they can't be read out onto the stack and
+ /// dropped normally.
+ ///
+ /// * It is friendlier to the optimizer to do this over `ptr::read` when
+ /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
+ /// as the compiler doesn't need to prove that it's sound to elide the
+ /// copy.
+ ///
+ /// # Safety
+ ///
+ /// This has all the same safety problems as `ptr::read` with respect to
+ /// invalid pointers, types, and double drops.
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn drop_in_place(self) {
+ drop_in_place(self)
+ }
+
+ /// Overwrites a memory location with the given value without reading or
+ /// dropping the old value.
+ ///
+ /// # Safety
+ ///
+ /// This operation is marked unsafe because it writes through a raw pointer.
+ ///
+ /// It does not drop the contents of `self`. This is safe, but it could leak
+ /// allocations or resources, so care must be taken not to overwrite an object
+ /// that should be dropped.
+ ///
+ /// Additionally, it does not drop `val`. Semantically, `val` is moved into the
+ /// location pointed to by `self`.
+ ///
+ /// This is appropriate for initializing uninitialized memory, or overwriting
+ /// memory that has previously been `read` from.
+ ///
+ /// The pointer must be aligned; use `write_unaligned` if that is not the case.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let mut x = 0;
+ /// let y = &mut x as *mut i32;
+ /// let z = 12;
+ ///
+ /// unsafe {
+ /// y.write(z);
+ /// assert_eq!(y.read(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn write(self, val: T)
+ where T: Sized,
+ {
+ write(self, val)
+ }
+
+ /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
+ /// bytes of memory starting at `self` to `val`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let mut vec = vec![0; 4];
+ /// unsafe {
+ /// let vec_ptr = vec.as_mut_ptr();
+ /// vec_ptr.write_bytes(b'a', 2);
+ /// }
+ /// assert_eq!(vec, [b'a', b'a', 0, 0]);
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn write_bytes(self, val: u8, count: usize)
+ where T: Sized,
+ {
+ write_bytes(self, val, count)
+ }
+
+ /// Performs a volatile write of a memory location with the given value without
+ /// reading or dropping the old value.
+ ///
+ /// Volatile operations are intended to act on I/O memory, and are guaranteed
+ /// to not be elided or reordered by the compiler across other volatile
+ /// operations.
+ ///
+ /// # Notes
+ ///
+ /// Rust does not currently have a rigorously and formally defined memory model,
+ /// so the precise semantics of what "volatile" means here is subject to change
+ /// over time. That being said, the semantics will almost always end up pretty
+ /// similar to [C11's definition of volatile][c11].
+ ///
+ /// The compiler shouldn't change the relative order or number of volatile
+ /// memory operations. However, volatile memory operations on zero-sized types
+ /// (e.g. if a zero-sized type is passed to `write_volatile`) are no-ops
+ /// and may be ignored.
+ ///
+ /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
+ ///
+ /// # Safety
+ ///
+ /// This operation is marked unsafe because it accepts a raw pointer.
+ ///
+ /// It does not drop the contents of `self`. This is safe, but it could leak
+ /// allocations or resources, so care must be taken not to overwrite an object
+ /// that should be dropped.
+ ///
+ /// This is appropriate for initializing uninitialized memory, or overwriting
+ /// memory that has previously been `read` from.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let mut x = 0;
+ /// let y = &mut x as *mut i32;
+ /// let z = 12;
+ ///
+ /// unsafe {
+ /// y.write_volatile(z);
+ /// assert_eq!(y.read_volatile(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn write_volatile(self, val: T)
+ where T: Sized,
+ {
+ write_volatile(self, val)
+ }
+
+ /// Overwrites a memory location with the given value without reading or
+ /// dropping the old value.
+ ///
+ /// Unlike `write`, the pointer may be unaligned.
+ ///
+ /// # Safety
+ ///
+ /// This operation is marked unsafe because it writes through a raw pointer.
+ ///
+ /// It does not drop the contents of `self`. This is safe, but it could leak
+ /// allocations or resources, so care must be taken not to overwrite an object
+ /// that should be dropped.
+ ///
+ /// Additionally, it does not drop `src`. Semantically, `src` is moved into the
+ /// location pointed to by `dst`.
+ ///
+ /// This is appropriate for initializing uninitialized memory, or overwriting
+ /// memory that has previously been `read` from.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(pointer_methods)]
+ ///
+ /// let mut x = 0;
+ /// let y = &mut x as *mut i32;
+ /// let z = 12;
+ ///
+ /// unsafe {
+ /// y.write_unaligned(z);
+ /// assert_eq!(y.read_unaligned(), 12);
+ /// }
+ /// ```
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn write_unaligned(self, val: T)
+ where T: Sized,
+ {
+ write_unaligned(self, val)
+ }
+
+ /// Replaces the value at `self` with `src`, returning the old
+ /// value, without dropping either.
+ ///
+ /// # Safety
+ ///
+ /// This is only unsafe because it accepts a raw pointer.
+ /// Otherwise, this operation is identical to `mem::replace`.
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn replace(self, src: T) -> T
+ where T: Sized,
+ {
+ replace(self, src)
+ }
+
+ /// Swaps the values at two mutable locations of the same type, without
+ /// deinitializing either. They may overlap, unlike `mem::swap` which is
+ /// otherwise equivalent.
+ ///
+ /// # Safety
+ ///
+ /// This function copies the memory through the raw pointers passed to it
+ /// as arguments.
+ ///
+ /// Ensure that these pointers are valid before calling `swap`.
+ #[unstable(feature = "pointer_methods", issue = "43941")]
+ #[inline]
+ pub unsafe fn swap(self, with: *mut T)
+ where T: Sized,
+ {
+ swap(self, with)
+ }
+}
+
+// Equality for pointers
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> PartialEq for *const T {
+ #[inline]
+ fn eq(&self, other: &*const T) -> bool { *self == *other }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Eq for *const T {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> PartialEq for *mut T {
+ #[inline]
+ fn eq(&self, other: &*mut T) -> bool { *self == *other }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: ?Sized> Eq for *mut T {}
+
+/// Compare raw pointers for equality.
+///
+/// This is the same as using the `==` operator, but less generic:
+/// the arguments have to be `*const T` raw pointers,
+/// not anything that implements `PartialEq`.
+///
+/// This can be used to compare `&T` references (which coerce to `*const T` implicitly)
+/// by their address rather than comparing the values they point to
+/// (which is what the `PartialEq for &T` implementation does).
+///
/// # Examples
///
/// ```
/// # Safety
///
/// `ptr` must be non-null.
+ #[unstable(feature = "unique", issue = "27730")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_unique_new"))]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
Unique { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData }
}
/// # Safety
///
/// `ptr` must be non-null.
+ #[unstable(feature = "shared", issue = "27730")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_shared_new"))]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
Shared { pointer: NonZero::new_unchecked(ptr), _marker: PhantomData }
}
// * The `raw` and `bytes` submodules.
// * Boilerplate trait implementations.
-use borrow::Borrow;
use cmp::Ordering::{self, Less, Equal, Greater};
use cmp;
use fmt;
fn as_ptr(&self) -> *const Self::Item;
#[stable(feature = "core", since = "1.6.0")]
- fn binary_search<Q: ?Sized>(&self, x: &Q) -> Result<usize, usize>
- where Self::Item: Borrow<Q>,
- Q: Ord;
+ fn binary_search(&self, x: &Self::Item) -> Result<usize, usize>
+ where Self::Item: Ord;
#[stable(feature = "core", since = "1.6.0")]
fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
where F: FnMut(&'a Self::Item) -> Ordering;
#[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
- fn binary_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, f: F) -> Result<usize, usize>
+ fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
where F: FnMut(&'a Self::Item) -> B,
- B: Borrow<Q>,
- Q: Ord;
+ B: Ord;
#[stable(feature = "core", since = "1.6.0")]
fn len(&self) -> usize;
m >= n && needle == &self[m-n..]
}
- fn binary_search<Q: ?Sized>(&self, x: &Q) -> Result<usize, usize>
- where T: Borrow<Q>,
- Q: Ord
+ fn binary_search(&self, x: &T) -> Result<usize, usize>
+ where T: Ord
{
- self.binary_search_by(|p| p.borrow().cmp(x))
+ self.binary_search_by(|p| p.cmp(x))
}
fn rotate(&mut self, mid: usize) {
}
#[inline]
- fn binary_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, mut f: F) -> Result<usize, usize>
+ fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
where F: FnMut(&'a Self::Item) -> B,
- B: Borrow<Q>,
- Q: Ord
+ B: Ord
{
- self.binary_search_by(|k| f(k).borrow().cmp(b))
+ self.binary_search_by(|k| f(k).cmp(b))
}
#[inline]
}
/// Converts a mutable slice of bytes to a mutable string slice.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // "Hello, Rust!" as a mutable vector
+/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33];
+///
+/// // As we know these bytes are valid, we can use `unwrap()`
+/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap();
+///
+/// assert_eq!("Hello, Rust!", outstr);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // Some invalid bytes in a mutable vector
+/// let mut invalid = vec![128, 223];
+///
+/// assert!(str::from_utf8_mut(&mut invalid).is_err());
+/// ```
+/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// errors that can be returned.
+///
+/// [error]: struct.Utf8Error.html
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
run_utf8_validation(v)?;
/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
///
/// [fromutf8]: fn.from_utf8_unchecked.html
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// let mut heart = vec![240, 159, 146, 150];
+/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) };
+///
+/// assert_eq!("💖", heart);
+/// ```
#[inline]
#[stable(feature = "str_mut_extras", since = "1.20.0")]
pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_atomic_bool_new"))]
pub const fn new(v: bool) -> AtomicBool {
AtomicBool { v: UnsafeCell::new(v as u8) }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_atomic_ptr_new"))]
pub const fn new(p: *mut T) -> AtomicPtr<T> {
AtomicPtr { p: UnsafeCell::new(p) }
}
#[cfg(target_has_atomic = "ptr")]
macro_rules! atomic_int {
- ($stable:meta,
+ ($stable:meta, $const_unstable:meta,
$stable_cxchg:meta,
$stable_debug:meta,
$stable_access:meta,
/// ```
#[inline]
#[$stable]
+ #[cfg_attr(not(stage0), $const_unstable)]
pub const fn new(v: $int_type) -> Self {
$atomic_type {v: UnsafeCell::new(v)}
}
#[cfg(target_has_atomic = "8")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_i8_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "8")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_u8_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "16")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_i16_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "16")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_u16_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "32")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_i32_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "32")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_u32_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "64")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_i64_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "64")]
atomic_int! {
unstable(feature = "integer_atomics", issue = "32976"),
+ rustc_const_unstable(feature = "const_atomic_u64_new"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
#[cfg(target_has_atomic = "ptr")]
atomic_int!{
stable(feature = "rust1", since = "1.0.0"),
+ rustc_const_unstable(feature = "const_atomic_isize_new"),
stable(feature = "extended_compare_and_swap", since = "1.10.0"),
stable(feature = "atomic_debug", since = "1.3.0"),
stable(feature = "atomic_access", since = "1.15.0"),
#[cfg(target_has_atomic = "ptr")]
atomic_int!{
stable(feature = "rust1", since = "1.0.0"),
+ rustc_const_unstable(feature = "const_atomic_usize_new"),
stable(feature = "extended_compare_and_swap", since = "1.10.0"),
stable(feature = "atomic_debug", since = "1.3.0"),
stable(feature = "atomic_access", since = "1.15.0"),
assert_eq!(i, ys.len());
}
+/// Test `FlatMap::fold` with items already picked off the front and back,
+/// to make sure all parts of the `FlatMap` are folded correctly.
+#[test]
+fn test_iterator_flat_map_fold() {
+ let xs = [0, 3, 6];
+ let ys = [1, 2, 3, 4, 5, 6, 7];
+ let mut it = xs.iter().flat_map(|&x| x..x+3);
+ it.next();
+ it.next_back();
+ let i = it.fold(0, |i, x| {
+ assert_eq!(x, ys[i]);
+ i + 1
+ });
+ assert_eq!(i, ys.len());
+}
+
#[test]
fn test_inspect() {
let xs = [1, 2, 3, 4];
#![deny(warnings)]
#![feature(box_syntax)]
-#![feature(const_fn)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(inclusive_range_syntax)]
#![feature(iter_rfind)]
#![feature(nonzero)]
-#![feature(ord_max_min)]
#![feature(rand)]
#![feature(raw)]
#![feature(refcell_replace_swap)]
#![feature(try_from)]
#![feature(unique)]
+#![feature(const_atomic_bool_new)]
+#![feature(const_atomic_usize_new)]
+#![feature(const_atomic_isize_new)]
+
extern crate core;
extern crate test;
extern crate rand;
pub fn new(nodes: &[DepNode],
edges: &[(DepNode, DepNode)])
-> DepGraphQuery {
- let mut graph = Graph::new();
+ let mut graph = Graph::with_capacity(nodes.len(), edges.len());
let mut indices = FxHashMap();
for node in nodes {
- indices.insert(node.clone(), graph.next_node_index());
- graph.add_node(node.clone());
+ indices.insert(node.clone(), graph.add_node(node.clone()));
}
for &(ref source, ref target) in edges {
//! get confused if the spans from leaf AST nodes occur in multiple places
//! in the HIR, especially for multiple identifiers.
+use dep_graph::DepGraph;
use hir;
use hir::map::{Definitions, DefKey};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
pub fn lower_crate(sess: &Session,
cstore: &CrateStore,
+ dep_graph: &DepGraph,
krate: &Crate,
resolver: &mut Resolver)
-> hir::Crate {
// We're constructing the HIR here; we don't care what we will
// read, since we haven't even constructed the *input* to
// incr. comp. yet.
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
LoweringContext {
crate_root: std_inject::injected_crate_name(krate),
use hir::map::DefPathHash;
use ich::{self, CachingCodemapView};
use session::config::DebugInfoLevel::NoDebugInfo;
-use ty;
+use ty::TyCtxt;
use util::nodemap::{NodeMap, ItemLocalMap};
use std::hash as std_hash;
/// a reference to the TyCtxt) and it holds a few caches for speeding up various
/// things (e.g. each DefId/DefPath is only hashed once).
pub struct StableHashingContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- tcx: ty::TyCtxt<'a, 'gcx, 'tcx>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
codemap: CachingCodemapView<'gcx>,
hash_spans: bool,
hash_bodies: bool,
impl<'a, 'gcx, 'tcx> StableHashingContext<'a, 'gcx, 'tcx> {
- pub fn new(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo;
let check_overflow_initial = tcx.sess.overflow_checks();
}
#[inline]
- pub fn tcx(&self) -> ty::TyCtxt<'a, 'gcx, 'tcx> {
+ pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
self.tcx
}
});
impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
-impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
+impl_stable_hash_for!(struct ::syntax::attr::Stability {
+ level,
+ feature,
+ rustc_depr,
+ rustc_const_unstable
+});
impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>>
for ::syntax::attr::StabilityLevel {
}
impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
+impl_stable_hash_for!(struct ::syntax::attr::RustcConstUnstable { feature });
impl_stable_hash_for!(enum ::syntax::attr::IntType {
found_it: false,
bound_region: self.bound_region,
hir_map: self.hir_map,
+ depth: self.depth,
};
intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
// this will visit only outermost type
hir_map: &'a hir::map::Map<'gcx>,
found_it: bool,
bound_region: ty::BoundRegion,
+ depth: u32,
}
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> {
}
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
- let br_index = match self.bound_region {
- ty::BrAnon(index) => index,
- _ => return,
- };
let hir_id = self.infcx.tcx.hir.node_to_hir_id(lifetime.id);
- match self.infcx.tcx.named_region(hir_id) {
+ match (self.infcx.tcx.named_region(hir_id), self.bound_region) {
// the lifetime of the TyPath!
- Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)) => {
- if debruijn_index.depth == 1 && anon_index == br_index {
+ (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
+ if debruijn_index.depth == self.depth && anon_index == br_index {
+ self.found_it = true;
+ return;
+ }
+ }
+
+ (Some(rl::Region::EarlyBound(_, id)), ty::BrNamed(def_id, _)) => {
+ debug!("EarlyBound self.infcx.tcx.hir.local_def_id(id)={:?} \
+ def_id={:?}",
+ self.infcx.tcx.hir.local_def_id(id),
+ def_id);
+ if self.infcx.tcx.hir.local_def_id(id) == def_id {
+ self.found_it = true;
+ return; // we can stop visiting now
+ }
+ }
+
+ (Some(rl::Region::LateBound(debruijn_index, id)), ty::BrNamed(def_id, _)) => {
+ debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
+ debruijn_index.depth);
+ debug!("self.infcx.tcx.hir.local_def_id(id)={:?}",
+ self.infcx.tcx.hir.local_def_id(id));
+ debug!("def_id={:?}", def_id);
+ if debruijn_index.depth == self.depth &&
+ self.infcx.tcx.hir.local_def_id(id) == def_id {
self.found_it = true;
+ return; // we can stop visiting now
}
}
- Some(rl::Region::Static) |
- Some(rl::Region::EarlyBound(_, _)) |
- Some(rl::Region::LateBound(_, _)) |
- Some(rl::Region::Free(_, _)) |
- None => {
+
+ (Some(rl::Region::Static), _) |
+ (Some(rl::Region::EarlyBound(_, _)), _) |
+ (Some(rl::Region::LateBound(_, _)), _) |
+ (Some(rl::Region::LateBoundAnon(_, _)), _) |
+ (Some(rl::Region::Free(_, _)), _) |
+ (None, _) => {
debug!("no arg found");
}
}
use hir::def_id::DefId;
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
-use ty::{self, Region, TyCtxt, TypeFoldable};
+use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
use ty::error::TypeError;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::{Pos, Span};
name: String,
sub: &ty::subst::Substs<'tcx>,
pos: usize,
- other_ty: &ty::Ty<'tcx>) {
+ other_ty: &Ty<'tcx>) {
// `value` and `other_value` hold two incomplete type representation for display.
// `name` is the path of both types being compared. `sub`
value.push_highlighted(name);
path: String,
sub: &ty::subst::Substs<'tcx>,
other_path: String,
- other_ty: &ty::Ty<'tcx>) -> Option<()> {
+ other_ty: &Ty<'tcx>) -> Option<()> {
for (i, ta) in sub.types().enumerate() {
if &ta == other_ty {
self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
/// Compare two given types, eliding parts that are the same between them and highlighting
/// relevant differences, and return two representation of those types for highlighted printing.
- fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>)
+ fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>)
-> (DiagnosticStyledString, DiagnosticStyledString)
{
match (&t1.sty, &t2.sty) {
}
fn expected_found_str_ty(&self,
- exp_found: &ty::error::ExpectedFound<ty::Ty<'tcx>>)
+ exp_found: &ty::error::ExpectedFound<Ty<'tcx>>)
-> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
let exp_found = self.resolve_type_vars_if_possible(exp_found);
if exp_found.references_error() {
//! anonymous regions.
use hir;
use infer::InferCtxt;
-use ty::{self, Region};
+use ty::{self, Region, Ty};
use hir::def_id::DefId;
use hir::map as hir_map;
// the argument corresponding to the anonymous region
pub arg: &'tcx hir::Arg,
// the type corresponding to the anonymopus region argument
- pub arg_ty: ty::Ty<'tcx>,
+ pub arg_ty: Ty<'tcx>,
// the ty::BoundRegion corresponding to the anonymous region
pub bound_region: ty::BoundRegion,
// corresponds to id the argument is the first parameter
}
}
- pub fn unsolved_variables(&self) -> Vec<ty::Ty<'tcx>> {
+ pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut variables = Vec::new();
let unbound_ty_vars = self.type_variables
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
-#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(i128_type)]
#![cfg_attr(windows, feature(libc))]
#![feature(trace_macros)]
#![feature(test)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
+
#![recursion_limit="256"]
extern crate arena;
}
}
+impl LangItem {
+ fn name(self) -> &'static str {
+ match self {
+ $( $variant => $name, )*
+ }
+ }
+}
+
pub struct LanguageItems {
pub items: Vec<Option<DefId>>,
pub missing: Vec<LangItem>,
&*self.items
}
- pub fn item_name(index: usize) -> &'static str {
- let item: Option<LangItem> = LangItem::from_u32(index as u32);
- match item {
- $( Some($variant) => $name, )*
- None => "???"
- }
- }
-
pub fn require(&self, it: LangItem) -> Result<DefId, String> {
- match self.items[it as usize] {
- Some(id) => Ok(id),
- None => {
- Err(format!("requires `{}` lang_item",
- LanguageItems::item_name(it as usize)))
- }
- }
- }
-
- pub fn require_owned_box(&self) -> Result<DefId, String> {
- self.require(OwnedBoxLangItem)
+ self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
}
pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
- let def_id_kinds = [
- (self.fn_trait(), ty::ClosureKind::Fn),
- (self.fn_mut_trait(), ty::ClosureKind::FnMut),
- (self.fn_once_trait(), ty::ClosureKind::FnOnce),
- ];
-
- for &(opt_def_id, kind) in &def_id_kinds {
- if Some(id) == opt_def_id {
- return Some(kind);
- }
+ match Some(id) {
+ x if x == self.fn_trait() => Some(ty::ClosureKind::Fn),
+ x if x == self.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
+ x if x == self.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+ _ => None
}
-
- None
}
$(
// Check for duplicates.
match self.items.items[item_index] {
Some(original_def_id) if original_def_id != item_def_id => {
- let name = LanguageItems::item_name(item_index);
+ let name = LangItem::from_u32(item_index as u32).unwrap().name();
let mut err = match self.tcx.hir.span_if_local(item_def_id) {
Some(span) => struct_span_err!(
self.tcx.sess,
PhantomDataItem, "phantom_data", phantom_data;
- // Deprecated:
- CovariantTypeItem, "covariant_type", covariant_type;
- ContravariantTypeItem, "contravariant_type", contravariant_type;
- InvariantTypeItem, "invariant_type", invariant_type;
- CovariantLifetimeItem, "covariant_lifetime", covariant_lifetime;
- ContravariantLifetimeItem, "contravariant_lifetime", contravariant_lifetime;
- InvariantLifetimeItem, "invariant_lifetime", invariant_lifetime;
-
NonZeroItem, "non_zero", non_zero;
DebugTraitLangItem, "debug_trait", debug_trait;
}
-impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
+impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> {
pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
self.lang_items().require(lang_item).unwrap_or_else(|msg| {
self.sess.fatal(&msg)
self.ir.tcx.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
&format!("variable `{}` is assigned to, but never used",
name),
- &format!("to disable this warning, consider using `_{}` instead",
+ &format!("to avoid this warning, consider using `_{}` instead",
name));
} else if name != "self" {
self.ir.tcx.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
&format!("unused variable: `{}`", name),
- &format!("to disable this warning, consider using `_{}` instead",
+ &format!("to avoid this warning, consider using `_{}` instead",
name));
}
}
},
feature: Symbol::intern("rustc_private"),
rustc_depr: None,
+ rustc_const_unstable: None,
});
annotator.parent_stab = Some(stability);
}
use hir::def::CtorKind;
use hir::def_id::DefId;
use ty::subst::{Subst, Substs};
-use ty::{self, AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior};
+use ty::{self, AdtDef, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use util::ppaux;
use rustc_back::slice;
}
impl<'tcx> TerminatorKind<'tcx> {
- pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
+ pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
TerminatorKind::SwitchInt {
impl<'tcx> Operand<'tcx> {
pub fn function_handle<'a>(
- tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
substs: &'tcx Substs<'tcx>,
span: Span,
#[cfg(test)]
mod tests {
- use dep_graph::DepGraph;
use errors;
use getopts;
use lint;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
- let dep_graph = DepGraph::new(false);
let matches =
&match optgroups().parse(&["--test".to_string()]) {
Ok(m) => m,
};
let registry = errors::registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess, cfg);
assert!(cfg.contains(&(Symbol::intern("test"), None)));
}
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
- let dep_graph = DepGraph::new(false);
let matches =
&match optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]) {
Ok(m) => m,
};
let registry = errors::registry::Registry::new(&[]);
let (sessopts, cfg) = build_session_options_and_crate_config(matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
let cfg = build_configuration(&sess, cfg);
let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test");
assert!(test_items.next().is_some());
#[test]
fn test_can_print_warnings() {
- let dep_graph = DepGraph::new(false);
{
let matches = optgroups().parse(&[
"-Awarnings".to_string()
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(!sess.diagnostic().can_emit_warnings);
}
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
}
]).unwrap();
let registry = errors::registry::Registry::new(&[]);
let (sessopts, _) = build_session_options_and_crate_config(&matches);
- let sess = build_session(sessopts, &dep_graph, None, registry);
+ let sess = build_session(sessopts, None, registry);
assert!(sess.diagnostic().can_emit_warnings);
}
}
pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
-use dep_graph::DepGraph;
use hir::def_id::{CrateNum, DefIndex};
use lint;
// Represents the data associated with a compilation
// session for a single crate.
pub struct Session {
- pub dep_graph: DepGraph,
pub target: config::Config,
pub host: Target,
pub opts: config::Options,
// forms a unique global identifier for the crate. It is used to allow
// multiple crates with the same name to coexist. See the
// trans::back::symbol_names module for more information.
- pub crate_disambiguator: RefCell<Symbol>,
+ pub crate_disambiguator: RefCell<Option<Symbol>>,
pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
impl Session {
pub fn local_crate_disambiguator(&self) -> Symbol {
- *self.crate_disambiguator.borrow()
+ match *self.crate_disambiguator.borrow() {
+ Some(sym) => sym,
+ None => bug!("accessing disambiguator before initialization"),
+ }
}
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
kind)
}
+ pub fn set_incr_session_load_dep_graph(&self, load: bool) {
+ let mut incr_comp_session = self.incr_comp_session.borrow_mut();
+
+ match *incr_comp_session {
+ IncrCompSession::Active { ref mut load_dep_graph, .. } => {
+ *load_dep_graph = load;
+ }
+ _ => {}
+ }
+ }
+
+ pub fn incr_session_load_dep_graph(&self) -> bool {
+ let incr_comp_session = self.incr_comp_session.borrow();
+ match *incr_comp_session {
+ IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph,
+ _ => false,
+ }
+ }
+
pub fn init_incr_comp_session(&self,
session_dir: PathBuf,
- lock_file: flock::Lock) {
+ lock_file: flock::Lock,
+ load_dep_graph: bool) {
let mut incr_comp_session = self.incr_comp_session.borrow_mut();
if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
*incr_comp_session = IncrCompSession::Active {
session_directory: session_dir,
lock_file,
+ load_dep_graph,
};
}
}
pub fn build_session(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry)
-> Session {
let file_path_mapping = sopts.file_path_mapping();
build_session_with_codemap(sopts,
- dep_graph,
local_crate_source_file,
registry,
Rc::new(codemap::CodeMap::new(file_path_mapping)),
}
pub fn build_session_with_codemap(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry,
codemap: Rc<codemap::CodeMap>,
emitter);
build_session_(sopts,
- dep_graph,
local_crate_source_file,
diagnostic_handler,
codemap)
}
pub fn build_session_(sopts: config::Options,
- dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
span_diagnostic: errors::Handler,
codemap: Rc<codemap::CodeMap>)
let working_dir = file_path_mapping.map_prefix(working_dir);
let sess = Session {
- dep_graph: dep_graph.clone(),
target: target_cfg,
host,
opts: sopts,
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FxHashMap()),
- crate_disambiguator: RefCell::new(Symbol::intern("")),
+ crate_disambiguator: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
type_length_limit: Cell::new(1048576),
Active {
session_directory: PathBuf,
lock_file: flock::Lock,
+ load_dep_graph: bool,
},
// This is the state after the session directory has been finalized. In this
// state, the contents of the directory must not be modified any more.
#[derive(Clone, PartialEq, Eq)]
pub struct VtableFnPointerData<'tcx, N> {
- pub fn_ty: ty::Ty<'tcx>,
+ pub fn_ty: Ty<'tcx>,
pub nested: Vec<N>
}
// except according to those terms.
use hir::def_id::DefId;
-use ty::{self, Ty, TypeFoldable, Substs};
+use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
use util::ppaux;
use std::fmt;
}
#[inline]
- pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+ pub fn def_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
tcx.type_of(self.def_id())
}
#[inline]
- pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
+ pub fn attrs<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
tcx.get_attrs(self.def_id())
}
}
Instance { def: InstanceDef::Item(def_id), substs: substs }
}
- pub fn mono(tcx: ty::TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
+ pub fn mono(tcx: TyCtxt<'a, 'tcx, 'b>, def_id: DefId) -> Instance<'tcx> {
Instance::new(def_id, tcx.global_tcx().empty_substs_for_def_id(def_id))
}
}
}
- pub fn to_ty<'a, 'tcx>(&self, tcx: &ty::TyCtxt<'a, 'tcx, 'tcx>,
+ pub fn to_ty<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>,
signed: bool) -> Ty<'tcx> {
match (*self, signed) {
(I1, false) => tcx.types.u8,
#![deny(warnings)]
#![forbid(unsafe_code)]
-#![feature(const_fn)]
#![feature(i128_type)]
#![feature(slice_patterns)]
#![feature(try_from)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(const_min_value))]
+#![cfg_attr(not(stage0), feature(const_max_value))]
+
#[macro_use]
extern crate rustc_bitflags;
pub fn target() -> TargetResult {
let mut base = super::android_base::opts();
- base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string();
+ base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+d16,-neon".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args
.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
use rustc::middle::mem_categorization::ImmutabilityBlame;
use rustc::middle::region;
use rustc::middle::free_region::RegionRelations;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
#[derive(Eq)]
pub struct LoanPath<'tcx> {
kind: LoanPathKind<'tcx>,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
}
impl<'tcx> PartialEq for LoanPath<'tcx> {
}
impl<'tcx> LoanPath<'tcx> {
- fn new(kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>) -> LoanPath<'tcx> {
+ fn new(kind: LoanPathKind<'tcx>, ty: Ty<'tcx>) -> LoanPath<'tcx> {
LoanPath { kind: kind, ty: ty }
}
- fn to_type(&self) -> ty::Ty<'tcx> { self.ty }
+ fn to_type(&self) -> Ty<'tcx> { self.ty }
}
// FIXME (pnkfelix): See discussion here
#![feature(slice_patterns)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_fn)]
#![feature(i128_type)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(const_min_value))]
+
extern crate arena;
#[macro_use] extern crate syntax;
#[macro_use] extern crate log;
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
-#![feature(const_fn)]
#![feature(i128)]
#![feature(i128_type)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(const_min_value))]
+#![cfg_attr(not(stage0), feature(const_max_value))]
+
extern crate rustc_apfloat;
extern crate syntax;
fn join(&self, pred1: usize, pred2: usize) -> usize;
}
+pub struct Intersect;
+impl BitwiseOperator for Intersect {
+ #[inline]
+ fn join(&self, a: usize, b: usize) -> usize { a & b }
+}
pub struct Union;
impl BitwiseOperator for Union {
#[inline]
}
}
+ pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> {
+ Graph {
+ nodes: SnapshotVec::with_capacity(nodes),
+ edges: SnapshotVec::with_capacity(edges),
+ }
+ }
+
// # Simple accessors
#[inline]
use std::ops::{Deref, DerefMut, Range};
use std::slice;
use bitslice::{BitSlice, Word};
-use bitslice::{bitwise, Union, Subtract};
+use bitslice::{bitwise, Union, Subtract, Intersect};
use indexed_vec::Idx;
/// Represents a set (or packed family of sets), of some element type
bitwise(self.words_mut(), other.words(), &Subtract)
}
+ pub fn intersect(&mut self, other: &IdxSet<T>) -> bool {
+ bitwise(self.words_mut(), other.words(), &Intersect)
+ }
+
pub fn iter(&self) -> Iter<T> {
Iter {
cur: None,
}
}
+ pub fn with_capacity(n: usize) -> SnapshotVec<D> {
+ SnapshotVec {
+ values: Vec::with_capacity(n),
+ undo_log: Vec::new(),
+ }
+ }
+
fn in_snapshot(&self) -> bool {
!self.undo_log.is_empty()
}
#![cfg_attr(not(feature="llvm"), allow(dead_code))]
+use rustc::dep_graph::DepGraph;
use rustc::hir::{self, map as hir_map};
use rustc::hir::lowering::lower_crate;
use rustc::ich::Fingerprint;
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
+ let (outputs, trans, dep_graph): (OutputFilenames, OngoingCrateTranslation, DepGraph) = {
let krate = match phase_1_parse_input(control, sess, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
- sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
+ sess,
+ &cstore,
+ krate,
+ registry,
+ &crate_name,
+ addl_plugins,
+ control.make_glob_map,
|expanded_crate| {
let mut state = CompileState::state_after_expand(
input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
}
}
- Ok((outputs, trans))
+ Ok((outputs, trans, tcx.dep_graph.clone()))
})??
};
sess.code_stats.borrow().print_type_sizes();
}
- let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
+ let (phase5_result, trans) = phase_5_run_llvm_passes(sess, &dep_graph, trans);
controller_entry_point!(after_llvm,
sess,
*sess.features.borrow_mut() = features;
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
- *sess.crate_disambiguator.borrow_mut() = Symbol::intern(&compute_crate_disambiguator(sess));
+
+ let disambiguator = Symbol::intern(&compute_crate_disambiguator(sess));
+ *sess.crate_disambiguator.borrow_mut() = Some(disambiguator);
+ rustc_incremental::prepare_session_directory(
+ sess,
+ &crate_name,
+ &disambiguator.as_str(),
+ );
+ let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
time(time_passes, "recursion limit", || {
middle::recursion_limit::update_limits(sess, &krate);
// item, much like we do for macro expansion. In other words, the hash reflects not just
// its contents but the results of name resolution on those contents. Hopefully we'll push
// this back at some point.
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name);
let resolver_arenas = Resolver::arenas();
let mut resolver = Resolver::new(sess,
// Lower ast -> hir.
let hir_forest = time(time_passes, "lowering ast -> hir", || {
- let hir_crate = lower_crate(sess, cstore, &krate, &mut resolver);
+ let hir_crate = lower_crate(sess, cstore, &dep_graph, &krate, &mut resolver);
if sess.opts.debugging_opts.hir_stats {
hir_stats::print_hir_stats(&hir_crate);
}
- hir_map::Forest::new(hir_crate, &sess.dep_graph)
+ hir_map::Forest::new(hir_crate, &dep_graph)
});
time(time_passes,
/// as a side effect.
#[cfg(feature="llvm")]
pub fn phase_5_run_llvm_passes(sess: &Session,
+ dep_graph: &DepGraph,
trans: write::OngoingCrateTranslation)
-> (CompileResult, trans::CrateTranslation) {
- let trans = trans.join(sess);
+ let trans = trans.join(sess, dep_graph);
if sess.opts.debugging_opts.incremental_info {
write::dump_incremental_data(&trans);
time(sess.time_passes(),
"serialize work products",
- move || rustc_incremental::save_work_products(sess));
+ move || rustc_incremental::save_work_products(sess, dep_graph));
(sess.compile_status(), trans)
}
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc::dep_graph::DepGraph;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::CompileIncomplete;
use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
},
};
- let dep_graph = DepGraph::new(sopts.build_dep_graph());
let cstore = Rc::new(CStore::new(box ::MetadataLoader));
let loader = file_loader.unwrap_or(box RealFileLoader);
let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
let mut sess = session::build_session_with_codemap(
- sopts, &dep_graph, input_file_path, descriptions, codemap, emitter_dest,
+ sopts, input_file_path, descriptions, codemap, emitter_dest,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
let control = callbacks.build_controller(&sess, &matches);
- (driver::compile_input(&sess, &cstore, &input, &odir, &ofile, Some(plugins), &control),
+ (driver::compile_input(&sess,
+ &cstore,
+ &input,
+ &odir,
+ &ofile,
+ Some(plugins),
+ &control),
Some(sess))
}
describe_lints(&ls, false);
return None;
}
- let dep_graph = DepGraph::new(sopts.build_dep_graph());
let mut sess = build_session(sopts.clone(),
- &dep_graph,
None,
descriptions.clone());
rustc_trans::init(&sess);
//! # Standalone Tests for the Inference Module
use driver;
-use rustc::dep_graph::DepGraph;
use rustc_lint;
use rustc_resolve::MakeGlobMap;
use rustc_trans;
options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box ::MetadataLoader));
let sess = session::build_session_(options,
- &dep_graph,
None,
diagnostic_handler,
Rc::new(CodeMap::new(FilePathMapping::empty())));
|_| Ok(()))
.expect("phase 2 aborted")
};
- let _ignore = dep_graph.in_ignore();
let arena = DroplessArena::new();
let arenas = ty::GlobalArenas::new();
pub use persist::save_trans_partition;
pub use persist::save_work_products;
pub use persist::in_incr_comp_dir;
+pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
//! unsupported file system and emit a warning in that case. This is not yet
//! implemented.
-use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc::hir::def_id::CrateNum;
use rustc::hir::svh::Svh;
use rustc::session::Session;
use rustc::ty::TyCtxt;
/// a dep-graph and work products from a previous session.
/// If the call fails, the fn may leave behind an invalid session directory.
/// The garbage collection will take care of it.
-pub fn prepare_session_directory(tcx: TyCtxt) -> Result<bool, ()> {
+pub fn prepare_session_directory(sess: &Session,
+ crate_name: &str,
+ crate_disambiguator: &str) {
+ if sess.opts.incremental.is_none() {
+ return
+ }
+
debug!("prepare_session_directory");
// {incr-comp-dir}/{crate-name-and-disambiguator}
- let crate_dir = crate_path_tcx(tcx, LOCAL_CRATE);
+ let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
debug!("crate-dir: {}", crate_dir.display());
- try!(create_dir(tcx.sess, &crate_dir, "crate"));
+ if create_dir(sess, &crate_dir, "crate").is_err() {
+ return
+ }
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
let crate_dir = match crate_dir.canonicalize() {
Ok(v) => v,
Err(err) => {
- tcx.sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
- crate_dir.display(), err));
- return Err(());
+ sess.err(&format!("incremental compilation: error canonicalizing path `{}`: {}",
+ crate_dir.display(), err));
+ return
}
};
// Lock the new session directory. If this fails, return an
// error without retrying
- let (directory_lock, lock_file_path) = try!(lock_directory(tcx.sess, &session_dir));
+ let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
+ Ok(e) => e,
+ Err(_) => return,
+ };
// Now that we have the lock, we can actually create the session
// directory
- try!(create_dir(tcx.sess, &session_dir, "session"));
+ if create_dir(sess, &session_dir, "session").is_err() {
+ return
+ }
// Find a suitable source directory to copy from. Ignore those that we
// have already tried before.
debug!("no source directory found. Continuing with empty session \
directory.");
- tcx.sess.init_incr_comp_session(session_dir, directory_lock);
- return Ok(false)
+ sess.init_incr_comp_session(session_dir, directory_lock, false);
+ return
};
debug!("attempting to copy data from source: {}",
source_directory.display());
- let print_file_copy_stats = tcx.sess.opts.debugging_opts.incremental_info;
+ let print_file_copy_stats = sess.opts.debugging_opts.incremental_info;
// Try copying over all files from the source directory
if let Ok(allows_links) = copy_files(&session_dir, &source_directory,
source_directory.display());
if !allows_links {
- tcx.sess.warn(&format!("Hard linking files in the incremental \
+ sess.warn(&format!("Hard linking files in the incremental \
compilation cache failed. Copying files \
instead. Consider moving the cache \
directory to a file system which supports \
);
}
- tcx.sess.init_incr_comp_session(session_dir, directory_lock);
- return Ok(true)
+ sess.init_incr_comp_session(session_dir, directory_lock, true);
+ return
} else {
debug!("copying failed - trying next directory");
// Try to remove the session directory we just allocated. We don't
// know if there's any garbage in it from the failed copy action.
if let Err(err) = safe_remove_dir_all(&session_dir) {
- tcx.sess.warn(&format!("Failed to delete partly initialized \
- session dir `{}`: {}",
- session_dir.display(),
- err));
+ sess.warn(&format!("Failed to delete partly initialized \
+ session dir `{}`: {}",
+ session_dir.display(),
+ err));
}
- delete_session_dir_lock_file(tcx.sess, &lock_file_path);
+ delete_session_dir_lock_file(sess, &lock_file_path);
mem::drop(directory_lock);
}
}
/// more general overview.
pub fn load_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
incremental_hashes_map: &IncrementalHashesMap) {
- if tcx.sess.opts.incremental.is_none() {
- return;
+ if tcx.sess.incr_session_load_dep_graph() {
+ let _ignore = tcx.dep_graph.in_ignore();
+ load_dep_graph_if_exists(tcx, incremental_hashes_map);
}
-
- match prepare_session_directory(tcx) {
- Ok(true) => {
- // We successfully allocated a session directory and there is
- // something in it to load, so continue
- }
- Ok(false) => {
- // We successfully allocated a session directory, but there is no
- // dep-graph data in it to load (because this is the first
- // compilation session with this incr. comp. dir.)
- return
- }
- Err(()) => {
- // Something went wrong while trying to allocate the session
- // directory. Don't try to use it any further.
- return
- }
- }
-
- let _ignore = tcx.dep_graph.in_ignore();
- load_dep_graph_if_exists(tcx, incremental_hashes_map);
}
fn load_dep_graph_if_exists<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mod work_product;
mod file_format;
+pub use self::fs::prepare_session_directory;
pub use self::fs::finalize_session_directory;
pub use self::fs::in_incr_comp_dir;
pub use self::load::load_dep_graph;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::dep_graph::DepNode;
+use rustc::dep_graph::{DepGraph, DepNode};
use rustc::hir::def_id::DefId;
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
¤t_metadata_hashes);
}
-pub fn save_work_products(sess: &Session) {
+pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
if sess.opts.incremental.is_none() {
return;
}
debug!("save_work_products()");
- let _ignore = sess.dep_graph.in_ignore();
+ let _ignore = dep_graph.in_ignore();
let path = work_products_path(sess);
- save_in(sess, path, |e| encode_work_products(sess, e));
+ save_in(sess, path, |e| encode_work_products(dep_graph, e));
// We also need to clean out old work-products, as not all of them are
// deleted during invalidation. Some object files don't change their
// content, they are just not needed anymore.
- let new_work_products = sess.dep_graph.work_products();
- let previous_work_products = sess.dep_graph.previous_work_products();
+ let new_work_products = dep_graph.work_products();
+ let previous_work_products = dep_graph.previous_work_products();
for (id, wp) in previous_work_products.iter() {
if !new_work_products.contains_key(id) {
Ok(())
}
-pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
- let work_products: Vec<_> = sess.dep_graph
+pub fn encode_work_products(dep_graph: &DepGraph,
+ encoder: &mut Encoder) -> io::Result<()> {
+ let work_products: Vec<_> = dep_graph
.work_products()
.iter()
.map(|(id, work_product)| {
//! This module contains files for saving intermediate work-products.
use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId};
+use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph};
use rustc::session::Session;
use rustc::session::config::OutputType;
use rustc::util::fs::link_or_copy;
use std::fs as std_fs;
pub fn save_trans_partition(sess: &Session,
+ dep_graph: &DepGraph,
cgu_name: &str,
partition_hash: u64,
files: &[(OutputType, PathBuf)]) {
saved_files,
};
- sess.dep_graph.insert_work_product(&work_product_id, work_product);
+ dep_graph.insert_work_product(&work_product_id, work_product);
}
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
- fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
- if let hir::ExprMatch(_, ref arms, _) = e.node {
- for a in arms {
- self.check_unused_mut_pat(cx, &a.pats)
- }
- }
+ fn check_arm(&mut self, cx: &LateContext, a: &hir::Arm) {
+ self.check_unused_mut_pat(cx, &a.pats)
}
- fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
- if let hir::StmtDecl(ref d, _) = s.node {
- if let hir::DeclLocal(ref l) = d.node {
- self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
- }
- }
+ fn check_local(&mut self, cx: &LateContext, l: &hir::Local) {
+ self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
}
fn check_fn(&mut self,
use schema::*;
use rustc::hir;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
#[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> {
}
struct NestedBodyCollector<'a, 'tcx: 'a> {
- tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
bodies_found: Vec<&'tcx hir::Body>,
}
use build::CFG;
use rustc::middle::region;
use rustc::mir::*;
-use rustc::ty;
+use rustc::ty::TyCtxt;
impl<'tcx> CFG<'tcx> {
pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
}
pub fn push_end_region<'a, 'gcx:'a+'tcx>(&mut self,
- tcx: ty::TyCtxt<'a, 'gcx, 'tcx>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
block: BasicBlock,
source_info: SourceInfo,
region_scope: region::Scope) {
use rustc_const_math::{ConstInt, ConstIsize};
use rustc::middle::const_val::ConstVal;
use rustc::middle::region;
-use rustc::ty;
+use rustc::ty::{self, Ty};
use rustc::mir::*;
use syntax::ast;
use syntax_pos::Span;
}
pub fn build_binary_op(&mut self, mut block: BasicBlock,
- op: BinOp, span: Span, ty: ty::Ty<'tcx>,
+ op: BinOp, span: Span, ty: Ty<'tcx>,
lhs: Operand<'tcx>, rhs: Operand<'tcx>) -> BlockAnd<Rvalue<'tcx>> {
let source_info = self.source_info(span);
let bool_ty = self.hir.bool_ty();
}
// Helper to get a `-1` value of the appropriate type
- fn neg_1_literal(&mut self, span: Span, ty: ty::Ty<'tcx>) -> Operand<'tcx> {
+ fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty {
ty::TyInt(ity) => {
let val = match ity {
}
// Helper to get the minimum value of the appropriate type
- fn minval_literal(&mut self, span: Span, ty: ty::Ty<'tcx>) -> Operand<'tcx> {
+ fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = match ty.sty {
ty::TyInt(ity) => {
let val = match ity {
use super::drop_flag_effects_for_location;
use super::on_lookup_result_bits;
+mod storage_liveness;
+
+pub use self::storage_liveness::*;
+
#[allow(dead_code)]
pub(super) mod borrows;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use super::*;
+
+use rustc::mir::*;
+use dataflow::BitDenotation;
+
+#[derive(Copy, Clone)]
+pub struct MaybeStorageLive<'a, 'tcx: 'a> {
+ mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> MaybeStorageLive<'a, 'tcx> {
+ pub fn new(mir: &'a Mir<'tcx>)
+ -> Self {
+ MaybeStorageLive { mir: mir }
+ }
+
+ pub fn mir(&self) -> &Mir<'tcx> {
+ self.mir
+ }
+}
+
+impl<'a, 'tcx> BitDenotation for MaybeStorageLive<'a, 'tcx> {
+ type Idx = Local;
+ fn name() -> &'static str { "maybe_storage_live" }
+ fn bits_per_block(&self) -> usize {
+ self.mir.local_decls.len()
+ }
+
+ fn start_block_effect(&self, _sets: &mut BlockSets<Local>) {
+ // Nothing is live on function entry
+ }
+
+ fn statement_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
+ match stmt.kind {
+ StatementKind::StorageLive(l) => sets.gen(&l),
+ StatementKind::StorageDead(l) => sets.kill(&l),
+ _ => (),
+ }
+ }
+
+ fn terminator_effect(&self,
+ _sets: &mut BlockSets<Local>,
+ _loc: Location) {
+ // Terminators have no effect
+ }
+
+ fn propagate_call_return(&self,
+ _in_out: &mut IdxSet<Local>,
+ _call_bb: mir::BasicBlock,
+ _dest_bb: mir::BasicBlock,
+ _dest_lval: &mir::Lvalue) {
+ // Nothing to do when a call returns successfully
+ }
+}
+
+impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
+ #[inline]
+ fn join(&self, pred1: usize, pred2: usize) -> usize {
+ pred1 | pred2 // "maybe" means we union effects of both preds
+ }
+}
+
+impl<'a, 'tcx> DataflowOperator for MaybeStorageLive<'a, 'tcx> {
+ #[inline]
+ fn bottom_value() -> bool {
+ false // bottom = dead
+ }
+}
use std::path::PathBuf;
use std::usize;
+pub use self::impls::{MaybeStorageLive};
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
pub use self::impls::{DefinitelyInitializedLvals};
pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
flow_state: &mut Self::FlowState);
}
+pub fn state_for_location<T: BitDenotation>(loc: Location,
+ analysis: &T,
+ result: &DataflowResults<T>)
+ -> IdxSetBuf<T::Idx> {
+ let mut entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
+
+ {
+ let mut sets = BlockSets {
+ on_entry: &mut entry.clone(),
+ kill_set: &mut entry.clone(),
+ gen_set: &mut entry,
+ };
+
+ for stmt in 0..loc.statement_index {
+ let mut stmt_loc = loc;
+ stmt_loc.statement_index = stmt;
+ analysis.statement_effect(&mut sets, stmt_loc);
+ }
+ }
+
+ entry
+}
+
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
{
flow_state: DataflowState<O>,
You can also have this error while using a cell type:
```compile_fail,E0492
-#![feature(const_fn)]
+#![feature(const_cell_new)]
use std::cell::Cell;
wrapper:
```
-#![feature(const_fn)]
+#![feature(const_cell_new)]
use std::cell::Cell;
use std::marker::Sync;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::ty::subst::Substs;
-use rustc::ty::{self, AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior};
+use rustc::ty::{AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior};
use rustc::hir;
use syntax::ast;
use syntax_pos::Span;
value: ExprRef<'tcx>,
},
Call {
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
fun: ExprRef<'tcx>,
args: Vec<ExprRef<'tcx>>,
},
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
use rustc_const_math::{ConstInt, ConstUsize};
providers.mir_shims = make_shim;
}
-fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: ty::InstanceDef<'tcx>)
-> &'tcx Mir<'tcx>
{
.collect()
}
-fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
ty: Option<Ty<'tcx>>)
-> Mir<'tcx>
pub struct DropShimElaborator<'a, 'tcx: 'a> {
pub mir: &'a Mir<'tcx>,
pub patch: MirPatch<'tcx>,
- pub tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+ pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
}
fn patch(&mut self) -> &mut MirPatch<'tcx> { &mut self.patch }
fn mir(&self) -> &'a Mir<'tcx> { self.mir }
- fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
+ fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
fn param_env(&self) -> ty::ParamEnv<'tcx> { self.param_env }
fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
}
/// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
-fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
- self_ty: ty::Ty<'tcx>)
+ self_ty: Ty<'tcx>)
-> Mir<'tcx>
{
debug!("build_clone_shim(def_id={:?})", def_id);
}
struct CloneShimBuilder<'a, 'tcx: 'a> {
- tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
}
impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
- fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Self {
+ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Self {
let sig = tcx.fn_sig(def_id);
let sig = tcx.erase_late_bound_regions(&sig);
let span = tcx.def_span(def_id);
self.block(vec![ret_statement], TerminatorKind::Return, false);
}
- fn make_lvalue(&mut self, mutability: Mutability, ty: ty::Ty<'tcx>) -> Lvalue<'tcx> {
+ fn make_lvalue(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Lvalue<'tcx> {
let span = self.span;
Lvalue::Local(
self.local_decls.push(temp_decl(mutability, ty, span))
fn make_clone_call(
&mut self,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
rcvr_field: Lvalue<'tcx>,
next: BasicBlock,
cleanup: BasicBlock
}
}
- fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: u64) {
+ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
let tcx = self.tcx;
let span = self.span;
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
self.block(vec![], TerminatorKind::Resume, true);
}
- fn tuple_shim(&mut self, tys: &ty::Slice<ty::Ty<'tcx>>) {
+ fn tuple_shim(&mut self, tys: &ty::Slice<Ty<'tcx>>) {
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
let mut returns = Vec::new();
///
/// If `untuple_args` is a vec of types, the second argument of the
/// function will be untupled as these types.
-fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
rcvr_adjustment: Adjustment,
call_kind: CallKind,
self.ctxt.mir
}
- fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.ctxt.tcx
}
//! This pass computes the meaning of the state field and the MIR locals which are live
//! across a suspension point. There are however two hardcoded generator states:
//! 0 - Generator have not been resumed yet
-//! 1 - Generator has been poisoned
+//! 1 - Generator has returned / is completed
+//! 2 - Generator has been poisoned
//!
//! It also rewrites `return x` and `yield y` as setting a new generator state and returning
//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
//! the action to take.
//!
//! One of them is the implementation of Generator::resume.
-//! For generators which have already returned it panics.
//! For generators with state 0 (unresumed) it starts the execution of the generator.
-//! For generators with state 1 (poisoned) it panics.
+//! For generators with state 1 (returned) and state 2 (poisoned) it panics.
//! Otherwise it continues the execution from the last suspension point.
//!
//! The other function is the drop glue for the generator.
-//! For generators which have already returned it does nothing.
//! For generators with state 0 (unresumed) it drops the upvars of the generator.
-//! For generators with state 1 (poisoned) it does nothing.
+//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
//! Otherwise it drops all the values in scope at the last suspension point.
use rustc::hir;
use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
-use rustc::mir::visit::{LvalueContext, MutVisitor};
+use rustc::mir::visit::{LvalueContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior};
use rustc::ty::subst::{Kind, Substs};
use util::dump_mir;
use util::liveness;
use rustc_const_math::ConstInt;
use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::indexed_set::IdxSetBuf;
use std::collections::HashMap;
use std::borrow::Cow;
use std::iter::once;
use std::mem;
use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
+use dataflow::{self, MaybeStorageLive, state_for_location};
pub struct StateTransform;
Local::new(1)
}
+struct SuspensionPoint {
+ state: u32,
+ resume: BasicBlock,
+ drop: Option<BasicBlock>,
+ storage_liveness: liveness::LocalSet,
+}
+
struct TransformVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
state_adt_ref: &'tcx AdtDef,
// Mapping from Local to (type of local, generator struct index)
remap: HashMap<Local, (Ty<'tcx>, usize)>,
- // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2
- bb_target_count: u32,
+ // A map from a suspension point in a block to the locals which have live storage at that point
+ storage_liveness: HashMap<BasicBlock, liveness::LocalSet>,
- // Map from a (which block to resume execution at, which block to use to drop the generator)
- // to a generator state
- bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
+ // A list of suspension points, generated during the transform
+ suspension_points: Vec<SuspensionPoint>,
// The original RETURN_POINTER local
new_ret_local: Local,
-
- // The block to resume execution when for Return
- return_block: BasicBlock,
}
impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
let ret_val = match data.terminator().kind {
TerminatorKind::Return => Some((1,
- self.return_block,
+ None,
Operand::Consume(Lvalue::Local(self.new_ret_local)),
None)),
TerminatorKind::Yield { ref value, resume, drop } => Some((0,
- resume,
+ Some(resume),
value.clone(),
drop)),
_ => None
};
if let Some((state_idx, resume, v, drop)) = ret_val {
- let bb_idx = {
- let bb_targets = &mut self.bb_targets;
- let bb_target = &mut self.bb_target_count;
- *bb_targets.entry((resume, drop)).or_insert_with(|| {
- let target = *bb_target;
- *bb_target = target.checked_add(1).unwrap();
- target
- })
- };
let source_info = data.terminator().source_info;
- data.statements.push(self.set_state(bb_idx, source_info));
+ // We must assign the value first in case it gets declared dead below
data.statements.push(Statement {
source_info,
kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER),
self.make_state(state_idx, v)),
});
+ let state = if let Some(resume) = resume { // Yield
+ let state = 3 + self.suspension_points.len() as u32;
+
+ self.suspension_points.push(SuspensionPoint {
+ state,
+ resume,
+ drop,
+ storage_liveness: self.storage_liveness.get(&block).unwrap().clone(),
+ });
+
+ state
+ } else { // Return
+ 1 // state for returned
+ };
+ data.statements.push(self.set_state(state, source_info));
data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
}
fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>,
mir: &mut Mir<'tcx>) -> Local {
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
let new_ret = LocalDecl {
mutability: Mutability::Mut,
ty: ret_ty,
name: None,
- source_info,
+ source_info: source_info(mir),
internal: false,
is_user_variable: false,
};
new_ret_local
}
+struct StorageIgnored(liveness::LocalSet);
+
+impl<'tcx> Visitor<'tcx> for StorageIgnored {
+ fn visit_statement(&mut self,
+ _block: BasicBlock,
+ statement: &Statement<'tcx>,
+ _location: Location) {
+ match statement.kind {
+ StatementKind::StorageLive(l) |
+ StatementKind::StorageDead(l) => { self.0.remove(&l); }
+ _ => (),
+ }
+ }
+}
+
fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
- source: MirSource) -> liveness::LocalSet {
+ source: MirSource) ->
+ (liveness::LocalSet,
+ HashMap<BasicBlock, liveness::LocalSet>) {
+ let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
+ let node_id = source.item_id();
+ let analysis = MaybeStorageLive::new(mir);
+ let storage_live =
+ dataflow::do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ |bd, p| &bd.mir().local_decls[p]);
+
+ let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
+ ignored.visit_mir(mir);
+
let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
- let result = liveness::liveness_of_locals(mir);
- liveness::dump_mir(tcx, "generator_liveness", source, mir, &result);
+ let liveness = liveness::liveness_of_locals(mir);
+ liveness::dump_mir(tcx, "generator_liveness", source, mir, &liveness);
+
+ let mut storage_liveness_map = HashMap::new();
for (block, data) in mir.basic_blocks().iter_enumerated() {
if let TerminatorKind::Yield { .. } = data.terminator().kind {
- set.union(&result.outs[block]);
+ let loc = Location {
+ block: block,
+ statement_index: data.statements.len(),
+ };
+
+ let storage_liveness = state_for_location(loc, &analysis, &storage_live);
+
+ storage_liveness_map.insert(block, storage_liveness.clone());
+
+ let mut live_locals = storage_liveness;
+
+ // Mark locals without storage statements as always having live storage
+ live_locals.union(&ignored.0);
+
+ // Locals live are live at this point only if they are used across suspension points
+ // and their storage is live
+ live_locals.intersect(&liveness.outs[block]);
+
+ // Add the locals life at this suspension point to the set of locals which live across
+ // any suspension points
+ set.union(&live_locals);
}
}
// The generator argument is ignored
set.remove(&self_arg());
- set
+ (set, storage_liveness_map)
}
fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
interior: GeneratorInterior<'tcx>,
mir: &mut Mir<'tcx>)
- -> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
+ -> (HashMap<Local, (Ty<'tcx>, usize)>,
+ GeneratorLayout<'tcx>,
+ HashMap<BasicBlock, liveness::LocalSet>)
{
// Use a liveness analysis to compute locals which are live across a suspension point
- let live_locals = locals_live_across_suspend_points(tcx, mir, source);
+ let (live_locals, storage_liveness) = locals_live_across_suspend_points(tcx, mir, source);
// Erase regions from the types passed in from typeck so we can compare them with
// MIR types
fields: vars
};
- (remap, layout)
+ (remap, layout, storage_liveness)
}
-fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>,
- block: BasicBlockData<'tcx>) {
- mir.basic_blocks_mut().raw.insert(0, block);
+fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &mut Mir<'tcx>,
+ cases: Vec<(u32, BasicBlock)>,
+ transform: &TransformVisitor<'a, 'tcx>) {
+ let return_block = insert_return_block(mir);
+
+ let switch = TerminatorKind::SwitchInt {
+ discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
+ switch_ty: tcx.types.u32,
+ values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
+ targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
+ };
+
+ let source_info = source_info(mir);
+ mir.basic_blocks_mut().raw.insert(0, BasicBlockData {
+ statements: Vec::new(),
+ terminator: Some(Terminator {
+ source_info,
+ kind: switch,
+ }),
+ is_cleanup: false,
+ });
let blocks = mir.basic_blocks_mut().iter_mut();
drop_clean: BasicBlock) -> Mir<'tcx> {
let mut mir = mir.clone();
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
+ let source_info = source_info(&mir);
- let return_block = BasicBlock::new(mir.basic_blocks().len());
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: TerminatorKind::Return,
- }),
- is_cleanup: false,
- });
-
- let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| {
- u.map(|d| (s, d))
- }).collect();
+ let mut cases = create_cases(&mut mir, transform, |point| point.drop);
cases.insert(0, (0, drop_clean));
- // The poisoned state 1 falls through to the default case which is just to return
+ // The returned state (1) and the poisoned state (2) falls through to
+ // the default case which is just to return
- let switch = TerminatorKind::SwitchInt {
- discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
- switch_ty: tcx.types.u32,
- values: Cow::from(cases.iter().map(|&(i, _)| {
- ConstInt::U32(i)
- }).collect::<Vec<_>>()),
- targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
- };
-
- insert_entry_point(&mut mir, BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: switch,
- }),
- is_cleanup: false,
- });
+ insert_switch(tcx, &mut mir, cases, &transform);
for block in mir.basic_blocks_mut() {
let kind = &mut block.terminator_mut().kind;
}
// Replace the return variable
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
mir.return_ty = tcx.mk_nil();
mir.local_decls[RETURN_POINTER] = LocalDecl {
mutability: Mutability::Mut,
mir
}
-fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &mut Mir<'tcx>) {
+fn insert_return_block<'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+ let return_block = BasicBlock::new(mir.basic_blocks().len());
+ let source_info = source_info(mir);
+ mir.basic_blocks_mut().push(BasicBlockData {
+ statements: Vec::new(),
+ terminator: Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Return,
+ }),
+ is_cleanup: false,
+ });
+ return_block
+}
+
+fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &mut Mir<'tcx>,
+ message: AssertMessage<'tcx>) -> BasicBlock {
let assert_block = BasicBlock::new(mir.basic_blocks().len());
let term = TerminatorKind::Assert {
cond: Operand::Constant(box Constant {
},
}),
expected: true,
- msg: AssertMessage::GeneratorResumedAfterReturn,
+ msg: message,
target: assert_block,
cleanup: None,
};
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
+ let source_info = source_info(mir);
mir.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator {
}),
is_cleanup: false,
});
+
+ assert_block
}
fn create_generator_resume_function<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mut transform: TransformVisitor<'a, 'tcx>,
+ transform: TransformVisitor<'a, 'tcx>,
def_id: DefId,
source: MirSource,
mir: &mut Mir<'tcx>) {
}
}
- let source_info = SourceInfo {
- span: mir.span,
- scope: ARGUMENT_VISIBILITY_SCOPE,
- };
-
- let poisoned_block = BasicBlock::new(mir.basic_blocks().len());
-
- let term = TerminatorKind::Assert {
- cond: Operand::Constant(box Constant {
- span: mir.span,
- ty: tcx.types.bool,
- literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Bool(false),
- ty: tcx.types.bool
- }),
- },
- }),
- expected: true,
- msg: AssertMessage::GeneratorResumedAfterPanic,
- target: transform.return_block,
- cleanup: None,
- };
-
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: term,
- }),
- is_cleanup: false,
- });
-
- transform.bb_targets.insert((poisoned_block, None), 1);
+ let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
- let switch = TerminatorKind::SwitchInt {
- discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
- switch_ty: tcx.types.u32,
- values: Cow::from(transform.bb_targets.values().map(|&i| {
- ConstInt::U32(i)
- }).collect::<Vec<_>>()),
- targets: transform.bb_targets.keys()
- .map(|&(k, _)| k)
- .chain(once(transform.return_block))
- .collect(),
- };
+ // Jump to the entry point on the 0 state
+ cases.insert(0, (0, BasicBlock::new(0)));
+ // Panic when resumed on the returned (1) state
+ cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
+ // Panic when resumed on the poisoned (2) state
+ cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
- insert_entry_point(mir, BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: switch,
- }),
- is_cleanup: false,
- });
+ insert_switch(tcx, mir, cases, &transform);
make_generator_state_argument_indirect(tcx, def_id, mir);
dump_mir(tcx, None, "generator_resume", &0, source, mir);
}
-fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
- let source_info = SourceInfo {
+fn source_info<'a, 'tcx>(mir: &Mir<'tcx>) -> SourceInfo {
+ SourceInfo {
span: mir.span,
scope: ARGUMENT_VISIBILITY_SCOPE,
- };
+ }
+}
- let return_block = BasicBlock::new(mir.basic_blocks().len());
- mir.basic_blocks_mut().push(BasicBlockData {
- statements: Vec::new(),
- terminator: Some(Terminator {
- source_info,
- kind: TerminatorKind::Return,
- }),
- is_cleanup: false,
- });
+fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
+ let return_block = insert_return_block(mir);
// Create a block to destroy an unresumed generators. This can only destroy upvars.
let drop_clean = BasicBlock::new(mir.basic_blocks().len());
target: return_block,
unwind: None,
};
+ let source_info = source_info(mir);
mir.basic_blocks_mut().push(BasicBlockData {
statements: Vec::new(),
terminator: Some(Terminator {
drop_clean
}
+fn create_cases<'a, 'tcx, F>(mir: &mut Mir<'tcx>,
+ transform: &TransformVisitor<'a, 'tcx>,
+ target: F) -> Vec<(u32, BasicBlock)>
+ where F: Fn(&SuspensionPoint) -> Option<BasicBlock> {
+ let source_info = source_info(mir);
+
+ transform.suspension_points.iter().filter_map(|point| {
+ // Find the target for this suspension point, if applicable
+ target(point).map(|target| {
+ let block = BasicBlock::new(mir.basic_blocks().len());
+ let mut statements = Vec::new();
+
+ // Create StorageLive instructions for locals with live storage
+ for i in 0..(mir.local_decls.len()) {
+ let l = Local::new(i);
+ if point.storage_liveness.contains(&l) && !transform.remap.contains_key(&l) {
+ statements.push(Statement {
+ source_info,
+ kind: StatementKind::StorageLive(l),
+ });
+ }
+ }
+
+ // Then jump to the real target
+ mir.basic_blocks_mut().push(BasicBlockData {
+ statements,
+ terminator: Some(Terminator {
+ source_info,
+ kind: TerminatorKind::Goto {
+ target,
+ },
+ }),
+ is_cleanup: false,
+ });
+
+ (point.state, block)
+ })
+ }).collect()
+}
+
impl MirPass for StateTransform {
fn run_pass<'a, 'tcx>(&self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Extract locals which are live across suspension point into `layout`
// `remap` gives a mapping from local indices onto generator struct indices
- let (remap, layout) = compute_layout(tcx, source, interior, mir);
+ // `storage_liveness` tells us which locals have live storage at suspension points
+ let (remap, layout, storage_liveness) = compute_layout(tcx, source, interior, mir);
let state_field = mir.upvar_decls.len();
- let mut bb_targets = HashMap::new();
-
- // If we jump to the entry point, we should go to the initial 0 generator state.
- // FIXME: Could this result in the need for destruction for state 0?
- bb_targets.insert((BasicBlock::new(0), None), 0);
-
// Run the transformation which converts Lvalues from Local to generator struct
// accesses for locals in `remap`.
// It also rewrites `return x` and `yield y` as writing a new generator state and returning
state_adt_ref,
state_substs,
remap,
- bb_target_count: 2,
- bb_targets,
+ storage_liveness,
+ suspension_points: Vec::new(),
new_ret_local,
state_field,
-
- // For returns we will resume execution at the next added basic block.
- // This happens in `insert_panic_on_resume_after_return`
- return_block: BasicBlock::new(mir.basic_blocks().len()),
};
transform.visit_mir(mir);
mir.spread_arg = None;
mir.generator_layout = Some(layout);
- // Panic if we resumed after returning
- insert_panic_on_resume_after_return(tcx, mir);
-
// Insert `drop(generator_struct)` which is used to drop upvars for generators in
// the unresumed (0) state.
// This is expanded to a drop ladder in `elaborate_generator_drops`.
use rustc::mir::visit::{LvalueContext, Visitor};
use rustc::middle::lang_items;
use syntax::abi::Abi;
+use syntax::attr;
use syntax::feature_gate::UnstableFeatures;
use syntax_pos::{Span, DUMMY_SP};
self.visit_operand(func, location);
let fn_ty = func.ty(self.mir, self.tcx);
- let (mut is_shuffle, mut is_const_fn) = (false, false);
+ let (mut is_shuffle, mut is_const_fn) = (false, None);
if let ty::TyFnDef(def_id, _) = fn_ty.sty {
match self.tcx.fn_sig(def_id).abi() {
Abi::RustIntrinsic |
Abi::PlatformIntrinsic => {
assert!(!self.tcx.is_const_fn(def_id));
match &self.tcx.item_name(def_id)[..] {
- "size_of" | "min_align_of" => is_const_fn = true,
+ "size_of" | "min_align_of" => is_const_fn = Some(def_id),
name if name.starts_with("simd_shuffle") => {
is_shuffle = true;
}
}
_ => {
- is_const_fn = self.tcx.is_const_fn(def_id);
+ if self.tcx.is_const_fn(def_id) {
+ is_const_fn = Some(def_id);
+ }
}
}
}
}
// Const fn calls.
- if is_const_fn {
- // We are in a const or static initializer,
- if self.mode != Mode::Fn &&
-
- // feature-gate is not enabled,
- !self.tcx.sess.features.borrow().const_fn &&
-
- // this doesn't come from a crate with the feature-gate enabled,
- self.def_id.is_local() &&
-
- // this doesn't come from a macro that has #[allow_internal_unstable]
- !self.span.allows_unstable()
- {
- let mut err = self.tcx.sess.struct_span_err(self.span,
- "const fns are an unstable feature");
- help!(&mut err,
- "in Nightly builds, add `#![feature(const_fn)]` \
- to the crate attributes to enable");
- err.emit();
+ if let Some(def_id) = is_const_fn {
+ // find corresponding rustc_const_unstable feature
+ if let Some(&attr::Stability {
+ rustc_const_unstable: Some(attr::RustcConstUnstable {
+ feature: ref feature_name
+ }),
+ .. }) = self.tcx.lookup_stability(def_id) {
+
+ // We are in a const or static initializer,
+ if self.mode != Mode::Fn &&
+
+ // feature-gate is not enabled,
+ !self.tcx.sess.features.borrow()
+ .declared_lib_features
+ .iter()
+ .any(|&(ref sym, _)| sym == feature_name) &&
+
+ // this doesn't come from a crate with the feature-gate enabled,
+ self.def_id.is_local() &&
+
+ // this doesn't come from a macro that has #[allow_internal_unstable]
+ !self.span.allows_unstable()
+ {
+ let mut err = self.tcx.sess.struct_span_err(self.span,
+ &format!("`{}` is not yet stable as a const fn",
+ self.tcx.item_path_str(def_id)));
+ help!(&mut err,
+ "in Nightly builds, add `#![feature({})]` \
+ to the crate attributes to enable",
+ feature_name);
+ err.emit();
+ }
}
} else {
self.qualif = Qualif::NOT_CONST;
use rustc::mir::*;
use rustc::middle::const_val::{ConstInt, ConstVal};
use rustc::middle::lang_items;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Substs};
use rustc::ty::util::IntTypeExt;
use rustc_data_structures::indexed_vec::Idx;
fn patch(&mut self) -> &mut MirPatch<'tcx>;
fn mir(&self) -> &'a Mir<'tcx>;
- fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx>;
+ fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
fn param_env(&self) -> ty::ParamEnv<'tcx>;
fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle;
lvalue.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx())
}
- fn tcx(&self) -> ty::TyCtxt<'b, 'tcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.elaborator.tcx()
}
pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) {
let envs = vec![("PATH".into(), command_path(sess))];
+ // If our linker looks like a batch script on Windows then to execute this
+ // we'll need to spawn `cmd` explicitly. This is primarily done to handle
+ // emscripten where the linker is `emcc.bat` and needs to be spawned as
+ // `cmd /c emcc.bat ...`.
+ //
+ // This worked historically but is needed manually since #42436 (regression
+ // was tagged as #42791) and some more info can be found on #44443 for
+ // emscripten itself.
+ let cmd = |linker: &str| {
+ if cfg!(windows) && linker.ends_with(".bat") {
+ let mut cmd = Command::new("cmd");
+ cmd.arg("/c").arg(linker);
+ cmd
+ } else {
+ Command::new(linker)
+ }
+ };
+
if let Some(ref linker) = sess.opts.cg.linker {
- (linker.clone(), Command::new(linker), envs)
+ (linker.clone(), cmd(linker), envs)
} else if sess.target.target.options.is_like_msvc {
let (cmd, envs) = msvc_link_exe_cmd(sess);
("link.exe".to_string(), cmd, envs)
} else {
let linker = &sess.target.target.options.linker;
- (linker.clone(), Command::new(&linker), envs)
+ (linker.clone(), cmd(linker), envs)
}
}
use back::linker::LinkerInfo;
use back::symbol_export::ExportedSymbols;
use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
+use rustc::dep_graph::DepGraph;
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
AllPasses, Sanitizer};
}
fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
+ dep_graph: &DepGraph,
compiled_modules: &CompiledModules,
crate_output: &OutputFilenames) {
if sess.opts.incremental.is_none() {
files.push((OutputType::Bitcode, path));
}
- save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
+ save_trans_partition(sess,
+ dep_graph,
+ &module.name,
+ module.symbol_name_hash,
+ &files);
}
}
}
impl OngoingCrateTranslation {
- pub fn join(self, sess: &Session) -> CrateTranslation {
+ pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
self.shared_emitter_main.check(sess, true);
let compiled_modules = match self.future.join() {
Ok(compiled_modules) => compiled_modules,
}
copy_module_artifacts_into_incr_comp_cache(sess,
+ dep_graph,
&compiled_modules,
&self.output_filenames);
produce_final_output_artifacts(sess,
use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
use rustc::traits;
use rustc::ty::subst::Substs;
-use rustc::ty::{self, TypeFoldable, TyCtxt};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::{self, Location};
use rustc::mir::visit::Visitor as MirVisitor;
}
fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
is_direct_call: bool,
output: &mut Vec<TransItem<'tcx>>)
{
}
fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
is_direct_call: bool,
output: &mut Vec<TransItem<'tcx>>)
{
/// Finally, there is also the case of custom unsizing coercions, e.g. for
/// smart pointers such as `Rc` and `Arc`.
fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- source_ty: ty::Ty<'tcx>,
- target_ty: ty::Ty<'tcx>)
- -> (ty::Ty<'tcx>, ty::Ty<'tcx>) {
- let ptr_vtable = |inner_source: ty::Ty<'tcx>, inner_target: ty::Ty<'tcx>| {
+ source_ty: Ty<'tcx>,
+ target_ty: Ty<'tcx>)
+ -> (Ty<'tcx>, Ty<'tcx>) {
+ let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
if !scx.type_is_sized(inner_source) {
(inner_source, inner_target)
} else {
/// Creates a `TransItem` for each method that is referenced by the vtable for
/// the given trait/impl pair.
fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- trait_ty: ty::Ty<'tcx>,
- impl_ty: ty::Ty<'tcx>,
+ trait_ty: Ty<'tcx>,
+ impl_ty: Ty<'tcx>,
output: &mut Vec<TransItem<'tcx>>) {
assert!(!trait_ty.needs_subst() && !trait_ty.has_escaping_regions() &&
!impl_ty.needs_subst() && !impl_ty.has_escaping_regions());
/// Cache instances of monomorphic and polymorphic items
instances: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
/// Cache generated vtables
- vtables: RefCell<FxHashMap<(ty::Ty<'tcx>,
+ vtables: RefCell<FxHashMap<(Ty<'tcx>,
Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>,
/// Cache of constant strings,
const_cstr_cache: RefCell<FxHashMap<InternedString, ValueRef>>,
}
pub fn vtables<'a>(&'a self)
- -> &'a RefCell<FxHashMap<(ty::Ty<'tcx>,
+ -> &'a RefCell<FxHashMap<(Ty<'tcx>,
Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>> {
&self.local().vtables
}
use llvm::{self, ValueRef};
use llvm::AttributePlace::Function;
-use rustc::ty;
+use rustc::ty::Ty;
use rustc::session::config::Sanitizer;
use abi::{Abi, FnType};
use attributes;
/// If there’s a value with the same name already declared, the function will
/// update the declaration and return existing ValueRef instead.
pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
- fn_type: ty::Ty<'tcx>) -> ValueRef {
+ fn_type: Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
let sig = common::ty_fn_sig(ccx, fn_type);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
/// can happen with #[no_mangle] or #[export_name], for example.
pub fn define_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
name: &str,
- fn_type: ty::Ty<'tcx>) -> ValueRef {
+ fn_type: Ty<'tcx>) -> ValueRef {
if get_defined_value(ccx, name).is_some() {
ccx.sess().fatal(&format!("symbol `{}` already defined", name))
} else {
/// can happen with #[no_mangle] or #[export_name], for example.
pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
name: &str,
- fn_type: ty::Ty<'tcx>) -> ValueRef {
+ fn_type: Ty<'tcx>) -> ValueRef {
let llfn = define_fn(ccx, name, fn_type);
unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
llfn
use llvm;
use llvm::{ValueRef};
-use rustc::traits;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty};
use rustc::ty::layout::LayoutTyper;
use common::*;
use meth;
use value::Value;
use builder::Builder;
-pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> bool {
- assert!(t.is_normalized_for_trans());
-
- let t = scx.tcx().erase_regions(&t);
-
- // FIXME (#22815): note that type_needs_drop conservatively
- // approximates in some cases and may say a type expression
- // requires drop glue when it actually does not.
- //
- // (In this case it is not clear whether any harm is done, i.e.
- // erroneously returning `true` in some cases where we could have
- // returned `false` does not appear unsound. The impact on
- // code quality is unknown at this time.)
-
- if !scx.type_needs_drop(t) {
- return false;
- }
- match t.sty {
- ty::TyAdt(def, _) if def.is_box() => {
- let typ = t.boxed_ty();
- if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
- let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap();
- if layout.size(scx).bytes() == 0 {
- // `Box<ZeroSizeType>` does not allocate.
- false
- } else {
- true
- }
- } else {
- true
- }
- }
- _ => true
- }
-}
-
pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
-> (ValueRef, ValueRef) {
debug!("calculate size of DST: {}; with lost info: {:?}",
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_fn)]
#![feature(custom_attribute)]
#![allow(unused_attributes)]
#![feature(i128_type)]
#![feature(slice_patterns)]
#![feature(conservative_impl_trait)]
+#![cfg_attr(stage0, feature(const_fn))]
+#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
+#![cfg_attr(not(stage0), feature(const_once_new))]
+
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
use monomorphize;
use type_::Type;
use value::Value;
-use rustc::ty;
+use rustc::ty::{self, Ty};
#[derive(Copy, Clone, Debug)]
pub struct VirtualIndex(usize);
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
/// `trait_ref` would map `T:Trait`.
pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>)
-> ValueRef
{
use llvm::{self, ValueRef, BasicBlockRef};
use rustc::middle::lang_items;
use rustc::middle::const_val::{ConstEvalErr, ConstInt, ErrKind};
-use rustc::ty::{self, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::layout::{self, LayoutTyper};
use rustc::mir;
use abi::{Abi, FnType, ArgType};
fn_ty: FnType<'tcx>,
fn_ptr: ValueRef,
llargs: &[ValueRef],
- destination: Option<(ReturnDest, ty::Ty<'tcx>, mir::BasicBlock)>,
+ destination: Option<(ReturnDest, Ty<'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>
| {
if let Some(cleanup) = cleanup {
use abi::Abi;
use common::*;
-use glue;
use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::DropInPlaceFnLangItem;
_ => {
if Some(def_id) == scx.tcx().lang_items().drop_in_place_fn() {
let ty = substs.type_at(0);
- if glue::needs_drop_glue(scx, ty) {
+ if scx.type_needs_drop(ty) {
debug!(" => nontrivial drop glue");
ty::InstanceDef::DropGlue(def_id, Some(ty))
} else {
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(const_fn)]
#![feature(custom_attribute)]
#![allow(unused_attributes)]
#![feature(i128_type)]
#![feature(slice_patterns)]
#![feature(conservative_impl_trait)]
+#![cfg_attr(stage0, feature(const_fn))]
+
extern crate rustc;
extern crate syntax;
extern crate syntax_pos;
///
pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
- ty: ty::Ty<'tcx>,
+ ty: Ty<'tcx>,
span: Span,
scope: region::Scope)
-> Result<(), ErrorReported>
tcx: TyCtxt<'a, 'tcx, 'tcx>,
position: &str,
span: Span,
- structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
- expected: &'a intrinsics::Type, t: ty::Ty<'tcx>)
+ structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, Ty<'tcx>>,
+ expected: &'a intrinsics::Type, t: Ty<'tcx>)
{
use intrinsics::Type::*;
use hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
-use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::ty::subst::Subst;
use rustc::infer::{self, InferOk};
pub fn method_exists(&self,
span: Span,
method_name: ast::Name,
- self_ty: ty::Ty<'tcx>,
+ self_ty: Ty<'tcx>,
call_expr_id: ast::NodeId,
allow_private: bool)
-> bool {
/// * `supplied_method_types`: the explicit method type parameters, if any (`T1..Tn`)
/// * `self_expr`: the self expression (`foo`)
pub fn lookup_method(&self,
- self_ty: ty::Ty<'tcx>,
+ self_ty: Ty<'tcx>,
segment: &hir::PathSegment,
span: Span,
call_expr: &'gcx hir::Expr,
fn lookup_probe(&self,
span: Span,
method_name: ast::Name,
- self_ty: ty::Ty<'tcx>,
+ self_ty: Ty<'tcx>,
call_expr: &'gcx hir::Expr,
scope: ProbeScope)
-> probe::PickResult<'tcx> {
span: Span,
m_name: ast::Name,
trait_def_id: DefId,
- self_ty: ty::Ty<'tcx>,
- opt_input_types: Option<&[ty::Ty<'tcx>]>)
+ self_ty: Ty<'tcx>,
+ opt_input_types: Option<&[Ty<'tcx>]>)
-> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("lookup_in_trait_adjusted(self_ty={:?}, \
m_name={}, trait_def_id={:?})",
pub fn resolve_ufcs(&self,
span: Span,
method_name: ast::Name,
- self_ty: ty::Ty<'tcx>,
+ self_ty: Ty<'tcx>,
expr_id: ast::NodeId)
-> Result<Def, MethodError<'tcx>> {
let mode = probe::Mode::Path;
use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::infer::UpvarRegion;
use syntax::ast;
use syntax_pos::Span;
}
}
-fn var_name(tcx: ty::TyCtxt, var_hir_id: hir::HirId) -> ast::Name {
+fn var_name(tcx: TyCtxt, var_hir_id: hir::HirId) -> ast::Name {
let var_node_id = tcx.hir.hir_to_node_id(var_hir_id);
tcx.hir.name(var_node_id)
}
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
method_sig: &hir::MethodSig,
method: &ty::AssociatedItem,
- self_ty: ty::Ty<'tcx>)
+ self_ty: Ty<'tcx>)
{
// check that the type of the method's receiver matches the
// method's first parameter.
/// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
/// built-in trait (formerly known as kind): Send.
pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
- param_ty: ty::Ty<'tcx>,
+ param_ty: Ty<'tcx>,
ast_bounds: &[hir::TyParamBound],
sized_by_default: SizedByDefault,
span: Span)
// ABIs are handled at all correctly.
if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic
&& !tcx.sess.features.borrow().simd_ffi {
- let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
+ let check = |ast_ty: &hir::Ty, ty: Ty| {
if ty.is_simd() {
tcx.sess.struct_span_err(ast_ty.span,
&format!("use of SIMD type `{}` in FFI is highly experimental and \
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use rustc::util::nodemap::FxHashSet;
}
}
-pub fn identify_constrained_type_params<'tcx>(tcx: ty::TyCtxt,
+pub fn identify_constrained_type_params<'tcx>(tcx: TyCtxt,
predicates: &[ty::Predicate<'tcx>],
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
input_parameters: &mut FxHashSet<Parameter>)
/// which is determined by 1, which requires `U`, that is determined
/// by 0. I should probably pick a less tangled example, but I can't
/// think of any.
-pub fn setup_constraining_predicates<'tcx>(tcx: ty::TyCtxt,
+pub fn setup_constraining_predicates<'tcx>(tcx: TyCtxt,
predicates: &mut [ty::Predicate<'tcx>],
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
input_parameters: &mut FxHashSet<Parameter>)
let all = vec![
(lang_items.phantom_data(), vec![ty::Covariant]),
(lang_items.unsafe_cell_type(), vec![ty::Invariant]),
-
- // Deprecated:
- (lang_items.covariant_type(), vec![ty::Covariant]),
- (lang_items.contravariant_type(), vec![ty::Contravariant]),
- (lang_items.invariant_type(), vec![ty::Invariant]),
- (lang_items.covariant_lifetime(), vec![ty::Covariant]),
- (lang_items.contravariant_lifetime(), vec![ty::Contravariant]),
- (lang_items.invariant_lifetime(), vec![ty::Invariant]),
-
];
all.into_iter() // iterating over (Option<DefId>, Variance)
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::traits::Reveal;
use rustc::ty::subst::Substs;
-use rustc::ty::{self, AdtKind};
+use rustc::ty::{self, Ty, AdtKind};
use rustc::middle::stability;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_typeck::hir_ty_to_ty;
}
}
-impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region<'tcx>> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
}
}
-impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
+impl<'tcx> Clean<Type> for Ty<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
match self.sty {
ty::TyNever => Never,
use rustc_lint;
use rustc_driver::{driver, target_features, abort_on_err};
use rustc_driver::pretty::ReplaceBodyWithLoop;
-use rustc::dep_graph::DepGraph;
use rustc::session::{self, config};
use rustc::hir::def_id::DefId;
use rustc::hir::def::Def;
false,
Some(codemap.clone()));
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, cpath, diagnostic_handler, codemap
+ sessopts, cpath, diagnostic_handler, codemap,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
/// Highlights `src`, returning the HTML output.
pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>,
- extension: Option<&str>) -> String {
+ extension: Option<&str>,
+ tooltip: Option<(&str, &str)>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::ParseSess::new(FilePathMapping::empty());
let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
let mut out = Vec::new();
+ if let Some((tooltip, class)) = tooltip {
+ write!(out, "<div class='information'><div class='tooltip {}'>⚠<span \
+ class='tooltiptext'>{}</span></div></div>",
+ class, tooltip).unwrap();
+ }
write_header(class, id, &mut out).unwrap();
let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm), sess.codemap());
fn next(&mut self) -> Option<Self::Item> {
let event = self.inner.next();
+ let compile_fail;
+ let ignore;
if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
- if !LangString::parse(&lang).rust {
+ let parse_result = LangString::parse(&lang);
+ if !parse_result.rust {
return Some(Event::Start(Tag::CodeBlock(lang)));
}
+ compile_fail = parse_result.compile_fail;
+ ignore = parse_result.ignore;
} else {
return event;
}
url, test_escaped, channel
))
});
+ let tooltip = if ignore {
+ Some(("Be careful when using this code, it's not being tested!", "ignore"))
+ } else if compile_fail {
+ Some(("This code doesn't compile so be extra careful!", "compile_fail"))
+ } else {
+ None
+ };
s.push_str(&highlight::render_with_highlighting(
&text,
- Some("rust-example-rendered"),
+ Some(&format!("rust-example-rendered{}",
+ if ignore { " ignore" }
+ else if compile_fail { " compile_fail" }
+ else { "" })),
None,
- playground_button.as_ref().map(String::as_str)));
+ playground_button.as_ref().map(String::as_str),
+ tooltip));
Some(Event::Html(s.into()))
})
}
let origtext = str::from_utf8(text).unwrap();
let origtext = origtext.trim_left();
debug!("docblock: ==============\n{:?}\n=======", text);
+ let mut compile_fail = false;
+ let mut ignore = false;
+
let rendered = if lang.is_null() || origtext.is_empty() {
false
} else {
let rlang = (*lang).as_bytes();
let rlang = str::from_utf8(rlang).unwrap();
- if !LangString::parse(rlang).rust {
+ let parse_result = LangString::parse(rlang);
+ compile_fail = parse_result.compile_fail;
+ ignore = parse_result.ignore;
+ if !parse_result.rust {
(my_opaque.dfltblk)(ob, orig_text, lang,
opaque as *const hoedown_renderer_data,
line);
url, test_escaped, channel
))
});
+ let tooltip = if ignore {
+ Some(("Be careful when using this code, it's not being tested!", "ignore"))
+ } else if compile_fail {
+ Some(("This code doesn't compile so be extra careful!", "compile_fail"))
+ } else {
+ None
+ };
s.push_str(&highlight::render_with_highlighting(
&text,
- Some("rust-example-rendered"),
+ Some(&format!("rust-example-rendered{}",
+ if ignore { " ignore" }
+ else if compile_fail { " compile_fail" }
+ else { "" })),
None,
- playground_button.as_ref().map(String::as_str)));
+ playground_button.as_ref().map(String::as_str),
+ tooltip));
hoedown_buffer_put(ob, s.as_ptr(), s.len());
})
}
let mut seen_rust_tags = false;
let mut seen_other_tags = false;
let mut data = LangString::all_false();
- let mut allow_compile_fail = false;
let mut allow_error_code_check = false;
if UnstableFeatures::from_environment().is_nightly_build() {
- allow_compile_fail = true;
allow_error_code_check = true;
}
data.test_harness = true;
seen_rust_tags = !seen_other_tags || seen_rust_tags;
}
- "compile_fail" if allow_compile_fail => {
+ "compile_fail" => {
data.compile_fail = true;
seen_rust_tags = !seen_other_tags || seen_rust_tags;
data.no_run = true;
use serialize::json::{ToJson, Json, as_json};
use syntax::{abi, ast};
-use syntax::feature_gate::UnstableFeatures;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
use rustc::middle::privacy::AccessLevels;
use rustc::middle::stability;
use rustc::hir;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc::session::config::nightly_options::is_nightly_build;
use rustc_data_structures::flock;
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability, Span};
prefix: &str,
scx: &SharedContext)
-> fmt::Result {
- let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
// We only emit warnings if the user has opted-in to Pulldown rendering.
let output = if render_type == RenderType::Pulldown {
+ // Save the state of USED_ID_MAP so it only gets updated once even
+ // though we're rendering twice.
+ let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+ let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+ USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
differences.retain(|s| {
pulldown_output
} else {
- hoedown_output
+ format!("{}", Markdown(md_text, RenderType::Hoedown))
};
write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
None,
None,
None,
+ None,
)
}
_ => String::new(),
fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
f: &clean::Function) -> fmt::Result {
- // FIXME(#24111): remove when `const_fn` is stabilized
- let vis_constness = match UnstableFeatures::from_environment() {
- UnstableFeatures::Allow => f.constness,
- _ => hir::Constness::NotConst
- };
let name_len = format!("{}{}{}{:#}fn {}{:#}",
VisSpace(&it.visibility),
- ConstnessSpace(vis_constness),
+ ConstnessSpace(f.constness),
UnsafetySpace(f.unsafety),
AbiSpace(f.abi),
it.name.as_ref().unwrap(),
write!(w, "{vis}{constness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}</pre>",
vis = VisSpace(&it.visibility),
- constness = ConstnessSpace(vis_constness),
+ constness = ConstnessSpace(f.constness),
unsafety = UnsafetySpace(f.unsafety),
abi = AbiSpace(f.abi),
name = it.name.as_ref().unwrap(),
href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
}
};
- // FIXME(#24111): remove when `const_fn` is stabilized
- let vis_constness = if is_nightly_build() {
- constness
- } else {
- hir::Constness::NotConst
- };
let mut head_len = format!("{}{}{:#}fn {}{:#}",
- ConstnessSpace(vis_constness),
+ ConstnessSpace(constness),
UnsafetySpace(unsafety),
AbiSpace(abi),
name,
};
write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
- ConstnessSpace(vis_constness),
+ ConstnessSpace(constness),
UnsafetySpace(unsafety),
AbiSpace(abi),
href = href,
write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols)?;
}
write!(fmt, "</pre>")?;
- write!(fmt, "{}", highlight::render_with_highlighting(s, None, None, None))?;
+ write!(fmt, "{}",
+ highlight::render_with_highlighting(s, None, None, None, None))?;
Ok(())
}
}
w.write_str(&highlight::render_with_highlighting(&t.source,
Some("macro"),
None,
+ None,
None))?;
document(w, cx, it)
}
collapseDocs(i_e.previousSibling.childNodes[0]);
});
});
+
+ onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {
+ if (hasClass(e, 'compile_fail')) {
+ e.addEventListener("mouseover", function(event) {
+ e.previousElementSibling.childNodes[0].style.color = '#f00';
+ });
+ e.addEventListener("mouseout", function(event) {
+ e.previousElementSibling.childNodes[0].style.color = '';
+ });
+ } else if (hasClass(e, 'ignore')) {
+ e.addEventListener("mouseover", function(event) {
+ e.previousElementSibling.childNodes[0].style.color = '#ff9200';
+ });
+ e.addEventListener("mouseout", function(event) {
+ e.previousElementSibling.childNodes[0].style.color = '';
+ });
+ }
+ });
}());
// Sets the focus on the search bar at the top of the page
font-weight: bold;
}
-pre.rust { position: relative; }
a.test-arrow {
display: inline-block;
position: absolute;
display: none;
}
}
+
+.information {
+ position: absolute;
+ left: -1px;
+ margin-top: 7px;
+}
+
+.tooltip {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+}
+
+.tooltip .tooltiptext {
+ width: 120px;
+ display: none;
+ background-color: black;
+ color: #fff;
+ text-align: center;
+ padding: 5px 3px;
+ border-radius: 6px;
+ margin-left: 5px;
+ top: -5px;
+ left: 105%;
+ z-index: 1;
+}
+
+.tooltip:hover .tooltiptext {
+ display: inline;
+}
+
+.tooltip .tooltiptext::after {
+ content: " ";
+ position: absolute;
+ top: 50%;
+ left: 11px;
+ margin-top: -5px;
+ border-width: 5px;
+ border-style: solid;
+ border-color: transparent black transparent transparent;
+}
:target > code {
background: #FDFFD3;
-}
\ No newline at end of file
+}
+
+pre.compile_fail {
+ border-left: 2px solid rgba(255,0,0,.4);
+}
+
+pre.compile_fail:hover, .information:hover + pre.compile_fail {
+ border-left: 2px solid #f00;
+}
+
+pre.ignore {
+ border-left: 2px solid rgba(255,142,0,.4);
+}
+
+pre.ignore:hover, .information:hover + pre.ignore {
+ border-left: 2px solid #ff9200;
+}
+
+.tooltip.compile_fail {
+ color: rgba(255,0,0,.3);
+}
+
+.information > .compile_fail:hover {
+ color: #f00;
+}
+
+.tooltip.ignore {
+ color: rgba(255,142,0,.3);
+}
+
+.information > .ignore:hover {
+ color: rgba(255,142,0,1);
+}
use testing;
use rustc_lint;
-use rustc::dep_graph::DepGraph;
use rustc::hir;
use rustc::hir::intravisit;
use rustc::session::{self, CompileIncomplete, config};
let handler =
errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, Some(input_path.clone()), handler, codemap.clone()
+ sessopts, Some(input_path.clone()), handler, codemap.clone(),
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let krate = ReplaceBodyWithLoop::new().fold_crate(krate);
let driver::ExpansionResult { defs, mut hir_forest, .. } = {
phase_2_configure_and_expand(
- &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+ &sess,
+ &cstore,
+ krate,
+ None,
+ "rustdoc-test",
+ None,
+ MakeGlobMap::No,
+ |_| Ok(()),
).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
render_type);
{
- let dep_graph = DepGraph::new(false);
- let _ignore = dep_graph.in_ignore();
let map = hir::map::map_crate(&mut hir_forest, defs);
let krate = map.krate();
let mut hir_collector = HirCollector {
// Compile the code
let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
- let dep_graph = DepGraph::new(false);
let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
let mut sess = session::build_session_(
- sessopts, &dep_graph, None, diagnostic_handler, codemap
+ sessopts, None, diagnostic_handler, codemap,
);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
/// Creates an empty `HashMap`.
///
+ /// The hash map is initially created with a capacity of 0, so it will not allocate until it
+ /// is first inserted into.
+ ///
/// # Examples
///
/// ```
impl<T: Hash + Eq> HashSet<T, RandomState> {
/// Creates an empty `HashSet`.
///
+ /// The hash set is initially created with a capacity of 0, so it will not allocate until it
+ /// is first inserted into.
+ ///
/// # Examples
///
/// ```
///
/// One maybe obvious note when using append-mode: make sure that all data
/// that belongs together is written to the file in one operation. This
- /// can be done by concatenating strings before passing them to `write()`,
+ /// can be done by concatenating strings before passing them to [`write()`],
/// or using a buffered writer (with a buffer of adequate size),
- /// and calling `flush()` when the message is complete.
+ /// and calling [`flush()`] when the message is complete.
///
/// If a file is opened with both read and append access, beware that after
/// opening, and after every write, the position for reading may be set at the
/// end of the file. So, before writing, save the current position (using
- /// `seek(SeekFrom::Current(0))`, and restore it before the next read.
+ /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`, and restore it before the next read.
+ ///
+ /// ## Note
+ ///
+ /// This function doesn't create the file if it doesn't exist. Use the [`create`]
+ /// method to do so.
+ ///
+ /// [`write()`]: ../../std/fs/struct.File.html#method.write
+ /// [`flush()`]: ../../std/fs/struct.File.html#method.flush
+ /// [`seek`]: ../../std/fs/struct.File.html#method.seek
+ /// [`SeekFrom`]: ../../std/io/enum.SeekFrom.html
+ /// [`Current`]: ../../std/io/enum.SeekFrom.html#variant.Current
+ /// [`create`]: #method.create
///
/// # Examples
///
/// This option indicates whether a new file will be created if the file
/// does not yet already exist.
///
- /// In order for the file to be created, `write` or `append` access must
+ /// In order for the file to be created, [`write`] or [`append`] access must
/// be used.
///
+ /// [`write`]: #method.write
+ /// [`append`]: #method.append
+ ///
/// # Examples
///
/// ```no_run
/// whether a file exists and creating a new one, the file may have been
/// created by another process (a TOCTOU race condition / attack).
///
- /// If `.create_new(true)` is set, `.create()` and `.truncate()` are
+ /// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
/// ignored.
///
/// The file must be opened with write or append access in order to create
/// a new file.
///
+ /// [`.create()`]: #method.create
+ /// [`.truncate()`]: #method.truncate
+ ///
/// # Examples
///
/// ```no_run
#![feature(raw)]
#![feature(repr_simd)]
#![feature(rustc_attrs)]
+#![cfg_attr(not(stage0), feature(rustc_const_unstable))]
#![feature(shared)]
#![feature(sip_hash_13)]
#![feature(slice_bytes)]
#![feature(doc_cfg)]
#![cfg_attr(test, feature(update_panic_count))]
+#![cfg_attr(not(stage0), feature(const_max_value))]
+#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_isize_new))]
+#![cfg_attr(not(stage0), feature(const_atomic_usize_new))]
+#![cfg_attr(all(not(stage0), windows), feature(const_atomic_ptr_new))]
+#![cfg_attr(not(stage0), feature(const_unsafe_cell_new))]
+#![cfg_attr(not(stage0), feature(const_cell_new))]
+#![cfg_attr(not(stage0), feature(const_once_new))]
+#![cfg_attr(not(stage0), feature(const_ptr_null))]
+#![cfg_attr(not(stage0), feature(const_ptr_null_mut))]
+
#![default_lib_allocator]
// Always use alloc_system during stage0 since we don't know if the alloc_*
#![unstable(feature = "ip", reason = "extra functionality has not been \
scrutinized to the level that it should \
- be stable",
+ be to be stable",
issue = "27709")]
use cmp::Ordering;
}
}
+ /// Creates a new IPv4 address with the address pointing to localhost: 127.0.0.1.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::localhost();
+ /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn localhost() -> Ipv4Addr {
+ Ipv4Addr::new(127, 0, 0, 1)
+ }
+
+ /// Creates a new IPv4 address representing an unspecified address: 0.0.0.0
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv4Addr;
+ ///
+ /// let addr = Ipv4Addr::unspecified();
+ /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn unspecified() -> Ipv4Addr {
+ Ipv4Addr::new(0, 0, 0, 0)
+ }
+
/// Returns the four eight-bit integers that make up this address.
///
/// # Examples
Ipv6Addr { inner: addr }
}
+ /// Creates a new IPv6 address representing localhost: `::1`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::localhost();
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn localhost() -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)
+ }
+
+ /// Creates a new IPv6 address representing the unspecified address: `::`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ip_constructors)]
+ /// use std::net::Ipv6Addr;
+ ///
+ /// let addr = Ipv6Addr::unspecified();
+ /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ /// ```
+ #[unstable(feature = "ip_constructors",
+ reason = "requires greater scrutiny before stabilization",
+ issue = "44582")]
+ pub fn unspecified() -> Ipv6Addr {
+ Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)
+ }
+
/// Returns the eight 16-bit segments that make up this address.
///
/// # Examples
assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
}
+ #[test]
+ fn ipv4_from_constructors() {
+ assert_eq!(Ipv4Addr::localhost(), Ipv4Addr::new(127, 0, 0, 1));
+ assert!(Ipv4Addr::localhost().is_loopback());
+ assert_eq!(Ipv4Addr::unspecified(), Ipv4Addr::new(0, 0, 0, 0));
+ assert!(Ipv4Addr::unspecified().is_unspecified());
+ }
+
+ #[test]
+ fn ipv6_from_contructors() {
+ assert_eq!(Ipv6Addr::localhost(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+ assert!(Ipv6Addr::localhost().is_loopback());
+ assert_eq!(Ipv6Addr::unspecified(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+ assert!(Ipv6Addr::unspecified().is_unspecified());
+ }
+
#[test]
fn ipv4_from_octets() {
assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
/// connection request.
///
/// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html
- #[unstable(feature = "tcpstream_connect_timeout", issue = "43079")]
+ #[stable(feature = "tcpstream_connect_timeout", since = "1.22.0")]
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream)
}
/// {
/// let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
///
-/// // read from the socket
+/// // Receives a single datagram message on the socket. If `buf` is too small to hold
+/// // the message, it will be cut off.
/// let mut buf = [0; 10];
/// let (amt, src) = socket.recv_from(&mut buf)?;
///
-/// // send a reply to the socket we received data from
+/// // Redeclare `buf` as slice of the received data and send reverse data back to origin.
/// let buf = &mut buf[..amt];
/// buf.reverse();
/// socket.send_to(buf, &src)?;
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
}
- /// Receives data from the socket. On success, returns the number of bytes
- /// read and the address from whence the data came.
+ /// Receives a single datagram message on the socket. On success, returns the number
+ /// of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// # Examples
///
/// let mut buf = [0; 10];
/// let (number_of_bytes, src_addr) = socket.recv_from(&mut buf)
/// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
self.0.recv_from(buf)
}
- /// Receives data from the socket, without removing it from the queue.
+ /// Receives a single datagram message on the socket, without removing it from the
+ /// queue. On success, returns the number of bytes read and the origin.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recvfrom` system call.
///
- /// On success, returns the number of bytes peeked and the address from
- /// whence the data came.
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
///
/// # Examples
///
/// let mut buf = [0; 10];
/// let (number_of_bytes, src_addr) = socket.peek_from(&mut buf)
/// .expect("Didn't receive data");
+ /// let filled_buf = &mut buf[..number_of_bytes];
/// ```
#[stable(feature = "peek", since = "1.18.0")]
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
/// receive data from the specified address.
///
/// If `addr` yields multiple addresses, `connect` will be attempted with
- /// each of the addresses until a connection is successful. If none of
- /// the addresses are able to be connected, the error returned from the
+ /// each of the addresses until the underlying OS function returns no
+ /// error. Note that usually, a successful `connect` call does not specify
+ /// that there is a remote server listening on the port, rather, such an
+ /// error would only be detected after the first send. If the OS returns an
+ /// error for each of the specified addresses, the error returned from the
/// last connection attempt (the last address) is returned.
///
/// # Examples
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// ```
///
- /// Create a UDP socket bound to `127.0.0.1:3400` and connect the socket to
- /// `127.0.0.1:8080`. If that connection fails, then the UDP socket will
- /// connect to `127.0.0.1:8081`:
- ///
- /// ```no_run
- /// use std::net::{SocketAddr, UdpSocket};
- ///
- /// let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
- /// let connect_addrs = [
- /// SocketAddr::from(([127, 0, 0, 1], 8080)),
- /// SocketAddr::from(([127, 0, 0, 1], 8081)),
- /// ];
- /// socket.connect(&connect_addrs[..]).expect("connect function failed");
- /// ```
+ /// Unlike in the TCP case, passing an array of addresses to the `connect`
+ /// function of a UDP socket is not a useful thing to do: The OS will be
+ /// unable to determine whether something is listening on the remote
+ /// address without the application sending data.
#[stable(feature = "net2_mutators", since = "1.9.0")]
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
super::each_addr(addr, |addr| self.0.connect(addr))
self.0.send(buf)
}
- /// Receives data on the socket from the remote address to which it is
- /// connected.
+ /// Receives a single datagram message on the socket from the remote address to
+ /// which it is connected. On success, returns the number of bytes read.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// The [`connect`] method will connect this socket to a remote address. This
/// method will fail if the socket is not connected.
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// let mut buf = [0; 10];
/// match socket.recv(&mut buf) {
- /// Ok(received) => println!("received {} bytes", received),
+ /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]),
/// Err(e) => println!("recv function failed: {:?}", e),
/// }
/// ```
self.0.recv(buf)
}
- /// Receives data on the socket from the remote address to which it is
- /// connected, without removing that data from the queue. On success,
- /// returns the number of bytes peeked.
+ /// Receives single datagram on the socket from the remote address to which it is
+ /// connected, without removing the message from input queue. On success, returns
+ /// the number of bytes peeked.
+ ///
+ /// The function must be called with valid byte array `buf` of sufficient size to
+ /// hold the message bytes. If a message is too long to fit in the supplied buffer,
+ /// excess bytes may be discarded.
///
/// Successive calls return the same data. This is accomplished by passing
/// `MSG_PEEK` as a flag to the underlying `recv` system call.
///
+ /// Do not use this function to implement busy waiting, instead use `libc::poll` to
+ /// synchronize IO events on one or more sockets.
+ ///
+ /// The [`connect`] method will connect this socket to a remote address. This
+ /// method will fail if the socket is not connected.
+ ///
+ /// [`connect`]: #method.connect
+ ///
/// # Errors
///
/// This method will fail if the socket is not connected. The `connect` method
impl Once {
/// Creates a new `Once` value.
#[stable(feature = "once_new", since = "1.2.0")]
+ #[cfg_attr(not(stage0), rustc_const_unstable(feature = "const_once_new"))]
pub const fn new() -> Once {
Once {
state: AtomicUsize::new(INCOMPLETE),
pub type HANDLE = LPVOID;
pub type HINSTANCE = HANDLE;
pub type HMODULE = HINSTANCE;
+pub type HRESULT = LONG;
pub type BOOL = c_int;
pub type BYTE = u8;
pub type BOOLEAN = BYTE;
pub const ERROR_IO_PENDING: DWORD = 997;
pub const ERROR_TIMEOUT: DWORD = 0x5B4;
+pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT;
+
pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
pub const FACILITY_NT_BIT: DWORD = 0x1000_0000;
timeout: *const timeval) -> c_int;
}
-// Functions that aren't available on Windows XP, but we still use them and just
-// provide some form of a fallback implementation.
+// Functions that aren't available on every version of Windows that we support,
+// but we still use them and just provide some form of a fallback implementation.
compat_fn! {
kernel32:
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL {
SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0
}
+ pub fn SetThreadDescription(hThread: HANDLE,
+ lpThreadDescription: LPCWSTR) -> HRESULT {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL
+ }
pub fn SetFileInformationByHandle(_hFile: HANDLE,
_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
_lpFileInformation: LPVOID,
use sys_common::thread::*;
use time::Duration;
+use super::to_u16s;
+
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
pub struct Thread {
}
}
- pub fn set_name(_name: &CStr) {
- // Windows threads are nameless
- // The names in MSVC debugger are obtained using a "magic" exception,
- // which requires a use of MS C++ extensions.
- // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+ pub fn set_name(name: &CStr) {
+ if let Ok(utf8) = name.to_str() {
+ if let Ok(utf16) = to_u16s(utf8) {
+ unsafe { c::SetThreadDescription(c::GetCurrentThread(), utf16.as_ptr()); };
+ };
+ };
}
pub fn join(self) {
}
}
-/// Represents the #[stable], #[unstable] and #[rustc_deprecated] attributes.
+/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
pub rustc_depr: Option<RustcDeprecation>,
+ pub rustc_const_unstable: Option<RustcConstUnstable>,
}
/// The available stability levels.
pub reason: Symbol,
}
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
+pub struct RustcConstUnstable {
+ pub feature: Symbol,
+}
+
#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
pub struct Deprecation {
pub since: Option<Symbol>,
{
let mut stab: Option<Stability> = None;
let mut rustc_depr: Option<RustcDeprecation> = None;
+ let mut rustc_const_unstable: Option<RustcConstUnstable> = None;
'outer: for attr in attrs_iter {
- if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" {
+ if ![
+ "rustc_deprecated",
+ "rustc_const_unstable",
+ "unstable",
+ "stable",
+ ].iter().any(|&s| attr.path == s) {
continue // not a stability level
}
}
};
- match &*meta.name.as_str() {
- "rustc_deprecated" => {
- if rustc_depr.is_some() {
- span_err!(diagnostic, item_sp, E0540,
- "multiple rustc_deprecated attributes");
- break
- }
-
- let mut since = None;
- let mut reason = None;
+ macro_rules! get_meta {
+ ($($name:ident),+) => {
+ $(
+ let mut $name = None;
+ )+
for meta in metas {
if let Some(mi) = meta.meta_item() {
match &*mi.name().as_str() {
- "since" => if !get(mi, &mut since) { continue 'outer },
- "reason" => if !get(mi, &mut reason) { continue 'outer },
+ $(
+ stringify!($name)
+ => if !get(mi, &mut $name) { continue 'outer },
+ )+
_ => {
handle_errors(diagnostic, mi.span,
AttrError::UnknownMetaItem(mi.name()));
continue 'outer
}
}
+ }
+ }
+
+ match &*meta.name.as_str() {
+ "rustc_deprecated" => {
+ if rustc_depr.is_some() {
+ span_err!(diagnostic, item_sp, E0540,
+ "multiple rustc_deprecated attributes");
+ continue 'outer
+ }
+
+ get_meta!(since, reason);
match (since, reason) {
(Some(since), Some(reason)) => {
}
}
}
+ "rustc_const_unstable" => {
+ if rustc_const_unstable.is_some() {
+ span_err!(diagnostic, item_sp, E0553,
+ "multiple rustc_const_unstable attributes");
+ continue 'outer
+ }
+
+ get_meta!(feature);
+ if let Some(feature) = feature {
+ rustc_const_unstable = Some(RustcConstUnstable {
+ feature
+ });
+ } else {
+ span_err!(diagnostic, attr.span(), E0629, "missing 'feature'");
+ continue
+ }
+ }
"unstable" => {
if stab.is_some() {
handle_errors(diagnostic, attr.span(), AttrError::MultipleStabilityLevels);
},
feature,
rustc_depr: None,
+ rustc_const_unstable: None,
})
}
(None, _, _) => {
},
feature,
rustc_depr: None,
+ rustc_const_unstable: None,
})
}
(None, _) => {
}
}
+ // Merge the const-unstable info into the stability info
+ if let Some(rustc_const_unstable) = rustc_const_unstable {
+ if let Some(ref mut stab) = stab {
+ stab.rustc_const_unstable = Some(rustc_const_unstable);
+ } else {
+ span_err!(diagnostic, item_sp, E0630,
+ "rustc_const_unstable attribute must be paired with \
+ either stable or unstable attribute");
+ }
+ }
+
stab
}
E0549, // rustc_deprecated attribute must be paired with either stable or unstable attribute
E0550, // multiple deprecated attributes
E0551, // incorrect meta item
+ E0553, // multiple rustc_const_unstable attributes
E0555, // malformed feature attribute, expected #![feature(...)]
E0556, // malformed feature, expected just one word
E0584, // file for module `..` found at both .. and ..
E0589, // invalid `repr(align)` attribute
+ E0629, // missing 'feature' (rustc_const_unstable)
+ E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute
}
pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
self.parse_sess.span_diagnostic.span_bug(sp, msg);
}
- pub fn trace_macros_diag(&self) {
+ pub fn trace_macros_diag(&mut self) {
for (sp, notes) in self.expansions.iter() {
let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
for note in notes {
}
db.emit();
}
+ // Fixme: does this result in errors?
+ self.expansions.clear();
}
pub fn bug(&self, msg: &str) -> ! {
self.parse_sess.span_diagnostic.bug(msg);
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
let info = self.cx.current_expansion.mark.expn_info().unwrap();
let suggested_limit = self.cx.ecfg.recursion_limit * 2;
- let mut err = self.cx.struct_span_fatal(info.call_site,
+ let mut err = self.cx.struct_span_err(info.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
info.callee.name()));
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
err.emit();
+ self.cx.trace_macros_diag();
panic!(FatalError);
}
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path));
+ self.cx.trace_macros_diag();
kind.dummy(attr.span)
}
_ => {
let msg = &format!("macro `{}` may not be used in attributes", attr.path);
self.cx.span_err(attr.span, msg);
+ self.cx.trace_macros_diag();
kind.dummy(attr.span)
}
}
if let Err(msg) = validate_and_set_expn_info(def_span.map(|(_, s)| s),
false, false) {
self.cx.span_err(path.span, &msg);
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
allow_internal_unstable,
allow_internal_unsafe) {
self.cx.span_err(path.span, &msg);
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
if ident.name == keywords::Invalid.name() {
self.cx.span_err(path.span,
&format!("macro {}! expects an ident argument", path));
+ self.cx.trace_macros_diag();
return kind.dummy(span);
};
MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
self.cx.span_err(path.span, &msg);
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
let msg = format!("non-{kind} macro in {kind} position: {name}",
name = path.segments[0].identifier.name, kind = kind.name());
self.cx.span_err(path.span, &msg);
+ self.cx.trace_macros_diag();
kind.dummy(span)
})
}
_ => {
let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
self.cx.span_err(span, msg);
+ self.cx.trace_macros_diag();
kind.dummy(span)
}
}
Ok(expansion) => expansion,
Err(mut err) => {
err.emit();
+ self.cx.trace_macros_diag();
return kind.dummy(span);
}
};
if !traits.is_empty() &&
(kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) {
self.cx.span_err(traits[0].span, "`derive` can be only be applied to items");
+ self.cx.trace_macros_diag();
return kind.expect_from_annotatables(::std::iter::once(item));
}
self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item })
}
let best_fail_msg = parse_failure_msg(best_fail_tok.expect("ran no matchers"));
- cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+ cx.span_err(best_fail_spot.substitute_dummy(sp), &best_fail_msg);
+ cx.trace_macros_diag();
+ DummyResult::any(sp)
}
// Note that macro-by-example's input is also matched against a token tree:
// rustc internal
(active, rustc_diagnostic_macros, "1.0.0", None),
+ (active, rustc_const_unstable, "1.0.0", None),
(active, advanced_slice_patterns, "1.0.0", Some(23121)),
(active, box_syntax, "1.0.0", Some(27779)),
(active, placement_in_syntax, "1.0.0", Some(27779)),
"the `#[rustc_on_unimplemented]` attribute \
is an experimental feature",
cfg_fn!(on_unimplemented))),
+ ("rustc_const_unstable", Normal, Gated(Stability::Unstable,
+ "rustc_const_unstable",
+ "the `#[rustc_const_unstable]` attribute \
+ is an internal feature",
+ cfg_fn!(rustc_const_unstable))),
("global_allocator", Normal, Gated(Stability::Unstable,
"global_allocator",
"the `#[global_allocator]` attribute is \
}
}
+impl From<Vec<Span>> for MultiSpan {
+ fn from(spans: Vec<Span>) -> MultiSpan {
+ MultiSpan::from_spans(spans)
+ }
+}
+
pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
/// Identifies an offset of a multi-byte character in a FileMap
// which is a reduction of this code to more directly show the reason
// for the error message we see here.)
-#![feature(const_fn, rustc_private)]
+#![feature(rustc_private)]
+#![feature(const_atomic_usize_new)]
extern crate arena;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
-
fn f(x: usize) -> usize {
x
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fns in std using individual feature gates.
+
+use std::cell::Cell;
+
+const CELL: Cell<i32> = Cell::new(42); //~ERROR not yet stable as a const fn
+ //~^HELP #![feature(const_cell_new)]
+
+fn main() {
+ let v = CELL.get();
+ CELL.set(v+1);
+
+ assert_eq!(CELL.get(), v);
+}
+
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test use of const fn from another crate without a feature gate.
-
-// aux-build:const_fn_lib.rs
-
-extern crate const_fn_lib;
-
-use const_fn_lib::foo;
-
-static FOO: usize = foo(); //~ ERROR const fns are an unstable feature
-const BAR: usize = foo(); //~ ERROR const fns are an unstable feature
-
-macro_rules! constant {
- ($n:ident: $t:ty = $v:expr) => {
- const $n: $t = $v;
- }
-}
-
-constant! {
- BAZ: usize = foo() //~ ERROR const fns are an unstable feature
-}
-
-fn main() {
-// let x: [usize; foo()] = [];
-}
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::cell::Cell;
use id::Id;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test internal const fn feature gate.
+
+#![feature(staged_api)]
+#![feature(const_fn)]
+//#![feature(rustc_const_unstable)]
+
+#[stable(feature="zing", since="1.0.0")]
+#[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature
+pub const fn bazinga() {}
+
+fn main() {
+}
+
// RFC 736 (and Issue 21407): functional struct update should respect privacy.
-#![feature(const_fn)]
-
// The `foo` module attempts to maintains an invariant that each `S`
// has a unique `u64` id.
use self::foo::S;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(const_unsafe_cell_new)]
use std::cell::UnsafeCell;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(const_fn, const_cell_new, const_unsafe_cell_new)]
#![feature(cfg_target_thread_local, thread_local_internals)]
// On platforms *without* `#[thread_local]`, use
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(box_syntax)]
-#![feature(const_fn)]
-#![allow(warnings)]
+#![feature(box_syntax, const_refcell_new)]
use std::cell::RefCell;
static boxed: Box<RefCell<isize>> = box RefCell::new(0);
//~^ ERROR allocations are not allowed in statics
//~| ERROR `std::cell::RefCell<isize>: std::marker::Sync` is not satisfied
+//~| WARN unsupported constant expr
fn main() { }
let mut a = 3;
let mut b = vec![2];
}
+
+// make sure the lint attribute can be turned off on let statements
+#[deny(unused_mut)]
+fn bar() {
+ #[allow(unused_mut)]
+ let mut a = 3;
+ let mut b = vec![2]; //~ ERROR: variable does not need to be mutable
+}
// Various checks that stability attributes are used correctly, per RFC 507
-#![feature(staged_api)]
+#![feature(const_fn, staged_api, rustc_const_unstable)]
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "a", since = "b")]
#[rustc_deprecated(since = "b", reason = "text")]
#[rustc_deprecated(since = "b", reason = "text")]
-fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
+#[rustc_const_unstable(feature = "a")]
+#[rustc_const_unstable(feature = "b")]
+pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
//~^ ERROR Invalid stability or deprecation version found
+//~| ERROR multiple rustc_const_unstable attributes
#[rustc_deprecated(since = "a", reason = "text")]
fn deprecated_without_unstable_or_stable() { }
#![allow(dead_code, unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
-#![feature(const_fn)]
+#![feature(const_unsafe_cell_new)]
#![feature(static_mutex)]
// This test makes sure that the compiler doesn't crash when trying to assign
opts.maybe_sysroot = Some(sysroot);
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
- let dep_graph = DepGraph::new(opts.build_dep_graph());
let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
- let sess = build_session(opts, &dep_graph, None, descriptions);
+ let sess = build_session(opts, None, descriptions);
rustc_trans::init(&sess);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
(sess, cstore)
// no-prefer-dynamic
#![allow(dead_code)]
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
// check dtor calling order when casting enums.
// `Item` originates in a where-clause, not the declaration of
// `T`. Issue #20300.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::marker::{PhantomData};
use std::sync::atomic::{AtomicUsize};
#![crate_type="rlib"]
#![feature(const_fn)]
-pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable
+pub const fn foo() -> usize { 22 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic;
// except according to those terms.
#![feature(cfg_target_thread_local, const_fn, thread_local)]
+#![feature(const_cell_new)]
#![crate_type = "lib"]
#[cfg(target_thread_local)]
// ignore-emscripten no threads support
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
// ignore-emscripten no threads support
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:const_fn_lib.rs
-
-// A very basic test of const fn functionality.
-
-#![feature(const_fn)]
-
-extern crate const_fn_lib;
-
-use const_fn_lib::foo;
-
-const FOO: usize = foo();
-
-fn main() {
- assert_eq!(FOO, 22);
- let _: [i32; foo()] = [42; 22];
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fns in std using individual feature gates.
+
+#![feature(const_cell_new)]
+
+use std::cell::Cell;
+
+const CELL: Cell<i32> = Cell::new(42);
+
+fn main() {
+ let v = CELL.get();
+ CELL.set(v+1);
+
+ assert_eq!(CELL.get(), v);
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fn from another crate without a feature gate.
+
+// aux-build:const_fn_lib.rs
+
+extern crate const_fn_lib;
+
+use const_fn_lib::foo;
+
+static FOO: usize = foo();
+const BAR: usize = foo();
+
+macro_rules! constant {
+ ($n:ident: $t:ty = $v:expr) => {
+ const $n: $t = $v;
+ }
+}
+
+constant! {
+ BAZ: usize = foo()
+}
+
+fn main() {
+ let x: [usize; foo()] = [42; foo()];
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(const_fn, const_size_of, const_align_of)]
use std::mem;
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+enum Enum {
+ A(String),
+ B
+}
+
+fn main() {
+ || {
+ loop {
+ if let true = true {
+ match Enum::A(String::new()) {
+ Enum::A(_var) => {}
+ Enum::B => {}
+ }
+ }
+ yield;
+ }
+ };
+}
\ No newline at end of file
// pretty-expanded FIXME #23616
#![feature(core)]
-#![feature(const_fn)]
-
+#![feature(const_unsafe_cell_new)]
use std::marker;
use std::cell::UnsafeCell;
#![feature(core)]
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
extern crate issue_17718_aux as other;
// created via FRU and control-flow breaks in the middle of
// construction.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic::{Ordering, AtomicUsize};
// ignore-emscripten no threads support
-#![feature(const_fn)]
-
// Check that the destructors of simple enums are run on unwinding
+#![feature(const_atomic_usize_new)]
+
use std::sync::atomic::{Ordering, AtomicUsize};
use std::thread;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic::{Ordering, AtomicUsize};
// the contents implement Drop and we hit a panic in the middle of
// construction.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
// ignore-emscripten no threads support
-#![feature(panic_handler, const_fn, std_panic)]
+#![feature(panic_handler, std_panic)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic::{AtomicUsize, Ordering};
use std::panic;
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(panic_handler, const_fn, std_panic)]
+#![feature(panic_handler, std_panic)]
+#![feature(const_atomic_usize_new)]
// ignore-emscripten no threads support
// Checks that functional-record-update order-of-eval is as expected
// even when no Drop-implementations are involved.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic::{Ordering, AtomicUsize};
// Checks that struct-literal expression order-of-eval is as expected
// even when no Drop-implementations are involved.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::sync::atomic::{Ordering, AtomicUsize};
// ignore-emscripten no threads support
-#![feature(const_fn)]
#![feature(rand)]
#![feature(sort_unstable)]
+#![feature(const_atomic_usize_new)]
use std::__rand::{thread_rng, Rng};
use std::cell::Cell;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/fn.bar.html '//*[@class="tooltip compile_fail"]/span' "This code doesn't compile so be extra careful!"
+// @has foo/fn.bar.html '//*[@class="tooltip ignore"]/span' "Be careful when using this code, it's not being tested!"
+
+/// foo
+///
+/// ```compile_fail
+/// foo();
+/// ```
+///
+/// ```ignore (tidy)
+/// goo();
+/// ```
+///
+/// ```
+/// let x = 0;
+/// ```
+pub fn bar() -> usize { 2 }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+#![crate_name = "foo"]
+
+// @has foo/fn.bar.html
+// @has - '//*[@class="rust fn"]' 'pub const fn bar() -> '
+/// foo
+pub const fn bar() -> usize {
+ 2
+}
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="method"]' 'const fn new()'
+pub struct Foo(usize);
+
+impl Foo {
+ pub const fn new() -> Foo { Foo(0) }
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a> {
+ x: &'a u32,
+}
+
+fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>)
+ where &'a (): Sized,
+ &'b u32: Sized
+{
+ x.push(y);
+}
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:12
+ |
+14 | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>)
+ | ------- ------- these two types are declared with different lifetimes...
+...
+18 | x.push(y);
+ | ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+struct Ref<'a> {
+ x: &'a u32,
+}
+
+fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>) {
+ x.push(y);
+}
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:12
+ |
+14 | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>) {
+ | ------- ------- these two types are declared with different lifetimes...
+15 | x.push(y);
+ | ^ ...but data from `y` flows into `x` here
+
+error: aborting due to previous error
+
12 | assert_eq!(1, 1,);
| ^
+error: aborting due to previous error
+
12 | assert_ne!(1, 2,);
| ^
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z trace-macros
+
+#![recursion_limit="4"]
+
+macro_rules! my_faulty_macro {
+ () => {
+ my_faulty_macro!(bcd);
+ };
+}
+
+macro_rules! pat_macro {
+ () => {
+ pat_macro!(A{a:a, b:0, c:_, ..});
+ };
+ ($a:pat) => {
+ $a
+ };
+}
+
+macro_rules! my_recursive_macro {
+ () => {
+ my_recursive_macro!();
+ };
+}
+
+macro_rules! my_macro {
+ () => {
+
+ };
+}
+
+fn main() {
+ my_faulty_macro!();
+ my_recursive_macro!();
+ test!();
+ non_exisiting!();
+ derive!(Debug);
+ let a = pat_macro!();
+}
+
+#[my_macro]
+fn use_bang_macro_as_attr(){}
+
+#[derive(Debug)]
+fn use_derive_macro_as_attr(){}
--- /dev/null
+error: no rules expected the token `bcd`
+ --> $DIR/trace_faulty_macros.rs:17:26
+ |
+17 | my_faulty_macro!(bcd);
+ | ^^^
+...
+43 | my_faulty_macro!();
+ | ------------------- in this macro invocation
+
+note: trace_macro
+ --> $DIR/trace_faulty_macros.rs:43:5
+ |
+43 | my_faulty_macro!();
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: expanding `my_faulty_macro! { }`
+ = note: to `my_faulty_macro ! ( bcd ) ;`
+ = note: expanding `my_faulty_macro! { bcd }`
+
+error: recursion limit reached while expanding the macro `my_recursive_macro`
+ --> $DIR/trace_faulty_macros.rs:32:9
+ |
+32 | my_recursive_macro!();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+44 | my_recursive_macro!();
+ | ---------------------- in this macro invocation
+ |
+ = help: consider adding a `#![recursion_limit="8"]` attribute to your crate
+
+note: trace_macro
+ --> $DIR/trace_faulty_macros.rs:44:5
+ |
+44 | my_recursive_macro!();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: expanding `my_recursive_macro! { }`
+ = note: to `my_recursive_macro ! ( ) ;`
+ = note: expanding `my_recursive_macro! { }`
+ = note: to `my_recursive_macro ! ( ) ;`
+ = note: expanding `my_recursive_macro! { }`
+ = note: to `my_recursive_macro ! ( ) ;`
+ = note: expanding `my_recursive_macro! { }`
+ = note: to `my_recursive_macro ! ( ) ;`
+ = note: expanding `my_recursive_macro! { }`
+ = note: to `my_recursive_macro ! ( ) ;`
+
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::cell::Cell;
use id::Id;
//
// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::cell::Cell;
use id::Id;
18 | #![warn(unused)]
| ^^^^^^
= note: #[warn(unused_variables)] implied by #[warn(unused)]
- = note: to disable this warning, consider using `_theOtherTwo` instead
+ = note: to avoid this warning, consider using `_theOtherTwo` instead
warning: variable `theTwo` should have a snake case name such as `the_two`
--> $DIR/issue-24690.rs:22:9
// conditions above to be satisfied, meaning that if the dropck is
// sound, it should reject this code.
-#![feature(const_fn)]
+#![feature(const_atomic_usize_new)]
use std::cell::Cell;
use id::Id;
-Subproject commit 8dd70945fb049df3f9dc7685cdc58d94e05e8ffc
+Subproject commit 52d48656f93eeeb2c568e6c1048e64168e5b209f
-Subproject commit adea17e1b22231a9036a619264b72565e3a3962f
+Subproject commit 0ddd53c4bc2a76df565a1c1fc0cc6f19f254b51e
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.0.22"
+version = "0.0.25"
default-features = false
extern crate clap;
use std::env;
-use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use clap::{App, ArgMatches, SubCommand, AppSettings};
use mdbook::MDBook;
+use mdbook::errors::Result;
fn main() {
let d_message = "-d, --dest-dir=[dest-dir]
::std::process::exit(101);
}
}
-
// Build command implementation
-fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
- let book = build_mdbook_struct(args);
+pub fn build(args: &ArgMatches) -> Result<()> {
+ let book_dir = get_book_dir(args);
+ let book = MDBook::new(&book_dir).read_config()?;
let mut book = match args.value_of("dest-dir") {
- Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
- None => book
+ Some(dest_dir) => book.with_destination(dest_dir),
+ None => book,
};
- try!(book.build());
+ book.build()?;
Ok(())
}
-fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
- let book_dir = get_book_dir(args);
- let mut book = MDBook::new(&book_dir).read_config();
-
- // By default mdbook will attempt to create non-existent files referenced
- // from SUMMARY.md files. This is problematic on CI where we mount the
- // source directory as readonly. To avoid any issues, we'll disabled
- // mdbook's implicit file creation feature.
- book.create_missing = false;
-
- book
-}
-
fn get_book_dir(args: &ArgMatches) -> PathBuf {
if let Some(dir) = args.value_of("dir") {
// Check if path is relative from current dir, or absolute...
--- /dev/null
+Subproject commit a1fd68da464fc51585f351c81fc2b867211c197e
"src/tools/rls",
"src/tools/clippy",
"src/tools/rust-installer",
+ "src/tools/rustfmt",
];
skip.iter().any(|p| path.ends_with(p))
}