diff --git a/.gitmodules b/.gitmodules index bdc14d8c3be71..9bc2a6a70eb45 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,7 +22,7 @@ path = src/doc/nomicon url = https://github.com/rust-lang-nursery/nomicon [submodule "src/tools/cargo"] - path = src/tools/cargo + path = cargo url = https://github.com/rust-lang/cargo [submodule "reference"] path = src/doc/reference diff --git a/.travis.yml b/.travis.yml index fa6c9cf074864..bbb0226a0c550 100644 --- a/.travis.yml +++ b/.travis.yml @@ -128,6 +128,7 @@ after_failure: echo "#### Build failed; Disk usage after running script:"; df -h; du . | sort -nr | head -n100 + - cat obj/tmp/sccache.log # Save tagged docker images we created and load them if they're available before_cache: diff --git a/appveyor.yml b/appveyor.yml index 9a0a4d81f9b1e..7409f83d967b0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -137,10 +137,10 @@ test_script: - sh src/ci/run.sh cache: - - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" - - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger" + - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" branches: only: diff --git a/src/tools/cargo b/cargo similarity index 100% rename from src/tools/cargo rename to cargo diff --git a/configure b/configure index be8628de62832..35b376d5f27b8 100755 --- a/configure +++ b/configure @@ -384,207 +384,6 @@ need_cmd sed need_cmd file need_cmd make -msg "inspecting environment" - -CFG_OSTYPE=$(uname -s) -CFG_CPUTYPE=$(uname -m) - -if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] -then - # Darwin's `uname -s` lies and always returns i386. We have to use sysctl - # instead. - if sysctl hw.optional.x86_64 | grep -q ': 1' - then - CFG_CPUTYPE=x86_64 - fi -fi - -# The goal here is to come up with the same triple as LLVM would, -# at least for the subset of platforms we're willing to target. - -case $CFG_OSTYPE in - - Linux) - CFG_OSTYPE=unknown-linux-gnu - ;; - - FreeBSD) - CFG_OSTYPE=unknown-freebsd - ;; - - DragonFly) - CFG_OSTYPE=unknown-dragonfly - ;; - - Bitrig) - CFG_OSTYPE=unknown-bitrig - ;; - - OpenBSD) - CFG_OSTYPE=unknown-openbsd - ;; - - NetBSD) - CFG_OSTYPE=unknown-netbsd - ;; - - Darwin) - CFG_OSTYPE=apple-darwin - ;; - - SunOS) - CFG_OSTYPE=sun-solaris - CFG_CPUTYPE=$(isainfo -n) - ;; - - Haiku) - CFG_OSTYPE=unknown-haiku - ;; - - MINGW*) - # msys' `uname` does not print gcc configuration, but prints msys - # configuration. so we cannot believe `uname -m`: - # msys1 is always i686 and msys2 is always x86_64. - # instead, msys defines $MSYSTEM which is MINGW32 on i686 and - # MINGW64 on x86_64. - CFG_CPUTYPE=i686 - CFG_OSTYPE=pc-windows-gnu - if [ "$MSYSTEM" = MINGW64 ] - then - CFG_CPUTYPE=x86_64 - fi - ;; - - MSYS*) - CFG_OSTYPE=pc-windows-gnu - ;; - -# Thad's Cygwin identifiers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=i686 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=pc-windows-gnu - CFG_CPUTYPE=x86_64 - ;; - -# Win 8 # uname -s on 64-bit cygwin does not contain WOW64, so simply use uname -m to detect arch (works in my install) - CYGWIN_NT-6.3) - CFG_OSTYPE=pc-windows-gnu - ;; -# We do not detect other OS such as XP/2003 using 64 bit using uname. -# If we want to in the future, we will need to use Cygwin - Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. - *) - err "unknown OS type: $CFG_OSTYPE" - ;; -esac - - -case $CFG_CPUTYPE in - - i386 | i486 | i686 | i786 | x86) - CFG_CPUTYPE=i686 - ;; - - xscale | arm) - CFG_CPUTYPE=arm - ;; - - armv6l) - CFG_CPUTYPE=arm - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - armv7l) - CFG_CPUTYPE=armv7 - CFG_OSTYPE="${CFG_OSTYPE}eabihf" - ;; - - aarch64 | arm64) - CFG_CPUTYPE=aarch64 - ;; - - powerpc | ppc) - CFG_CPUTYPE=powerpc - ;; - - powerpc64 | ppc64) - CFG_CPUTYPE=powerpc64 - ;; - - powerpc64le | ppc64le) - CFG_CPUTYPE=powerpc64le - ;; - - s390x) - CFG_CPUTYPE=s390x - ;; - - x86_64 | x86-64 | x64 | amd64) - CFG_CPUTYPE=x86_64 - ;; - - mips | mips64) - if [ "$CFG_CPUTYPE" = "mips64" ]; then - CFG_OSTYPE="${CFG_OSTYPE}abi64" - fi - ENDIAN=$(printf '\1' | od -dAn) - if [ "$ENDIAN" -eq 1 ]; then - CFG_CPUTYPE="${CFG_CPUTYPE}el" - elif [ "$ENDIAN" -ne 256 ]; then - err "unknown endianness: $ENDIAN (expecting 1 for little or 256 for big)" - fi - ;; - - BePC) - CFG_CPUTYPE=i686 - ;; - - *) - err "unknown CPU type: $CFG_CPUTYPE" -esac - -# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation -if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] -then - # $SHELL does not exist in standard 'sh', so probably only exists - # if configure is running in an interactive bash shell. /usr/bin/env - # exists *everywhere*. - BIN_TO_PROBE="$SHELL" - if [ ! -r "$BIN_TO_PROBE" ]; then - if [ -r "/usr/bin/env" ]; then - BIN_TO_PROBE="/usr/bin/env" - else - warn "Cannot check if the userland is i686 or x86_64" - fi - fi - file -L "$BIN_TO_PROBE" | grep -q "x86[_-]64" - if [ $? != 0 ]; then - msg "i686 userland on x86_64 Linux kernel" - CFG_CPUTYPE=i686 - fi -fi - - -DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}" - CFG_SRC_DIR="$(abs_path $(dirname $0))/" CFG_SRC_DIR_RELATIVE="$(dirname $0)/" CFG_BUILD_DIR="$(pwd)/" @@ -638,6 +437,7 @@ opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt local-rebuild 0 "assume local-rust matches the current version, for rebuilds; implies local-rust, and is implied if local-rust already matches the current version" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt llvm-link-shared 0 "prefer shared linking to LLVM (llvm-config --link-shared)" +opt llvm-clean-rebuild 0 "delete LLVM build directory on rebuild" opt rpath 1 "build rpaths into rustc itself" opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0" # This is used by the automation to produce single-target nightlies @@ -673,7 +473,7 @@ valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" -valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" +valopt build "" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" @@ -821,76 +621,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi -# If we have no git directory then we are probably a tarball distribution -# and shouldn't attempt to load submodules -if [ ! -e ${CFG_SRC_DIR}.git ] -then - probe CFG_GIT git - msg "git: no git directory. disabling submodules" - CFG_DISABLE_MANAGE_SUBMODULES=1 -else - probe_need CFG_GIT git -fi - -# Use `md5sum` on GNU platforms, or `md5 -q` on BSD -probe CFG_MD5 md5 -probe CFG_MD5SUM md5sum -if [ -n "$CFG_MD5" ] -then - CFG_HASH_COMMAND="$CFG_MD5 -q | cut -c 1-8" -elif [ -n "$CFG_MD5SUM" ] -then - CFG_HASH_COMMAND="$CFG_MD5SUM | cut -c 1-8" -else - err 'could not find one of: md5 md5sum' -fi -putvar CFG_HASH_COMMAND - -probe CFG_CLANG clang++ -probe CFG_CCACHE ccache -probe CFG_GCC gcc -probe CFG_LD ld -probe CFG_VALGRIND valgrind -probe CFG_PERF perf -probe CFG_ISCC iscc -probe CFG_ANTLR4 antlr4 -probe CFG_GRUN grun -probe CFG_FLEX flex -probe CFG_BISON bison -probe CFG_GDB gdb -probe CFG_LLDB lldb - -if [ -n "$CFG_ENABLE_NINJA" ] -then - probe CFG_NINJA ninja - if [ -z "$CFG_NINJA" ] - then - # On Debian and Fedora, the `ninja` binary is an IRC bot, so the build tool was - # renamed. Handle this case. - probe CFG_NINJA ninja-build - fi -fi - -# For building LLVM -if [ -z "$CFG_LLVM_ROOT" ] -then - probe_need CFG_CMAKE cmake -fi - -# On MacOS X, invoking `javac` pops up a dialog if the JDK is not -# installed. Since `javac` is only used if `antlr4` is available, -# probe for it only in this case. -if [ -n "$CFG_ANTLR4" ] -then - CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - if [ "x" = "x$CFG_ANTLR4_JAR" ] - then - CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\"" - fi - putvar CFG_ANTLR4_JAR $CFG_ANTLR4_JAR - probe CFG_JAVAC javac -fi - # the valgrind rpass tests will fail if you don't have a valgrind, but they're # only disabled if you opt out. if [ -z "$CFG_VALGRIND" ] @@ -905,41 +635,6 @@ then fi fi -if [ -n "$CFG_LLDB" ] -then - # Store LLDB's version - CFG_LLDB_VERSION=$($CFG_LLDB --version 2>/dev/null | head -1) - putvar CFG_LLDB_VERSION - - # If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from - # LLDB via the -P commandline options. - if [ -z "$CFG_LLDB_PYTHON_DIR" ] || [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR=$($CFG_LLDB -P) - - # If CFG_LLDB_PYTHON_DIR is not a valid directory, set it to something more readable - if [ ! -d "$CFG_LLDB_PYTHON_DIR" ] - then - CFG_LLDB_PYTHON_DIR="LLDB_PYTHON_DIRECTORY_NOT_FOUND" - fi - - putvar CFG_LLDB_PYTHON_DIR - fi -fi - -# LLDB tests on OSX require /usr/bin/python, not something like Homebrew's -# /usr/local/bin/python. We're loading a compiled module for LLDB tests which is -# only compatible with the system. -case $CFG_BUILD in - *-apple-darwin) - CFG_LLDB_PYTHON=/usr/bin/python - ;; - *) - CFG_LLDB_PYTHON=$CFG_PYTHON - ;; -esac -putvar CFG_LLDB_PYTHON - # Do some sanity checks if running on buildbot # (these env vars are set by rust-buildbot) if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then @@ -952,10 +647,6 @@ if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then fi fi -step_msg "looking for target specific programs" - -probe CFG_ADB adb - BIN_SUF= if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ] then @@ -1021,10 +712,6 @@ CFG_MANDIR=${CFG_MANDIR%/} CFG_DOCDIR=${CFG_DOCDIR%/} CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')" CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')" -CFG_SUPPORTED_TARGET="" -for target_file in ${CFG_SRC_DIR}mk/cfg/*.mk; do - CFG_SUPPORTED_TARGET="${CFG_SUPPORTED_TARGET} $(basename "$target_file" .mk)" -done # copy build-triples to host-triples so that builds are a subset of hosts V_TEMP="" @@ -1064,31 +751,6 @@ putvar CFG_MANDIR putvar CFG_DOCDIR putvar CFG_USING_LIBCPP -# Avoid spurious warnings from clang by feeding it original source on -# ccache-miss rather than preprocessed input. -if [ -n "$CFG_ENABLE_CCACHE" ] && [ -n "$CFG_USING_CLANG" ] -then - CFG_CCACHE_CPP2=1 - putvar CFG_CCACHE_CPP2 -fi - -if [ -n "$CFG_ENABLE_CCACHE" ] -then - CFG_CCACHE_BASEDIR=${CFG_SRC_DIR} - putvar CFG_CCACHE_BASEDIR -fi - - -putvar CFG_LLVM_SRC_DIR - -for t in $CFG_HOST -do - CFG_LLVM_BUILD_DIR=$(echo CFG_LLVM_BUILD_DIR_${t} | tr - _) - CFG_LLVM_INST_DIR=$(echo CFG_LLVM_INST_DIR_${t} | tr - _) - putvar $CFG_LLVM_BUILD_DIR - putvar $CFG_LLVM_INST_DIR -done - msg copy_if_changed ${CFG_SRC_DIR}src/bootstrap/mk/Makefile.in ./Makefile move_if_changed config.tmp config.mk diff --git a/src/Cargo.lock b/src/Cargo.lock index f4174693a5771..7ed8757dbb438 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -6,23 +6,6 @@ dependencies = [ "libc 0.0.0", ] -[[package]] -name = "advapi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "aho-corasick" version = "0.6.2" @@ -90,11 +73,6 @@ dependencies = [ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bufstream" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "build-manifest" version = "0.1.0" @@ -110,81 +88,10 @@ dependencies = [ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cargo" -version = "0.18.0" -dependencies = [ - "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargotest 0.1.0", - "crates-io 0.7.0", - "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargotest" -version = "0.1.0" -dependencies = [ - "bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo 0.18.0", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargotest2" version = "0.1.0" -[[package]] -name = "cfg-if" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "clap" version = "2.20.5" @@ -230,9 +137,9 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -240,58 +147,6 @@ dependencies = [ name = "core" version = "0.0.0" -[[package]] -name = "crates-io" -version = "0.7.0" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "curl" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "curl-sys" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "docopt" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dtoa" version = "0.4.1" @@ -299,18 +154,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "env_logger" -version = "0.3.5" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -334,48 +181,15 @@ dependencies = [ "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "flate2" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "fmt_macros" version = "0.0.0" -[[package]] -name = "foreign-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fs2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "gcc" version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "gdi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getopts" version = "0.0.0" @@ -385,55 +199,17 @@ name = "getopts" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "git2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "git2-curl" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "graphviz" version = "0.0.0" -[[package]] -name = "hamcrest" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "handlebars" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -441,16 +217,6 @@ dependencies = [ "serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "idna" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.3.1" @@ -482,59 +248,13 @@ name = "libc" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libgit2-sys" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libssh2-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libz-sys" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "linkchecker" version = "0.1.0" [[package]] name = "log" -version = "0.0.0" - -[[package]] -name = "log" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "matches" -version = "0.1.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -543,9 +263,9 @@ version = "0.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (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.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -554,14 +274,6 @@ dependencies = [ "toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "1.0.1" @@ -570,99 +282,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miniz-sys" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miow" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "net2" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-bigint" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-complex" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.36" @@ -676,48 +295,11 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num_cpus" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "open" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "openssl" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "openssl-probe" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "openssl-sys" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "panic_abort" version = "0.0.0" @@ -741,11 +323,6 @@ name = "pest" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pkg-config" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc_macro" version = "0.0.0" @@ -762,15 +339,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "psapi-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pulldown-cmark" version = "0.0.8" @@ -793,11 +361,6 @@ name = "quick-error" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand" version = "0.0.0" @@ -805,26 +368,6 @@ dependencies = [ "core 0.0.0", ] -[[package]] -name = "rand" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "0.2.1" @@ -837,11 +380,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.4.0" @@ -862,7 +400,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -902,7 +440,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -916,7 +454,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -931,7 +469,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -953,7 +491,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -962,8 +500,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1002,7 +541,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1014,7 +553,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1046,7 +585,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1065,7 +604,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -1089,7 +628,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -1128,7 +667,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1139,7 +678,7 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -1151,7 +690,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -1183,7 +722,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1201,8 +740,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1218,50 +758,11 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "semver" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "serde_codegen_internals" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_ignored" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "serde_json" version = "0.9.7" @@ -1277,11 +778,6 @@ dependencies = [ name = "serialize" version = "0.0.0" -[[package]] -name = "shell-escape" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "std" version = "0.0.0" @@ -1318,29 +814,11 @@ name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "syn" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -1353,7 +831,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1367,36 +845,10 @@ dependencies = [ "serialize 0.0.0", ] -[[package]] -name = "tar" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term" version = "0.0.0" -[[package]] -name = "term" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "term_size" version = "0.2.3" @@ -1415,15 +867,6 @@ dependencies = [ "term 0.0.0", ] -[[package]] -name = "thread-id" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread-id" version = "3.0.0" @@ -1433,14 +876,6 @@ dependencies = [ "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread_local" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.3" @@ -1470,19 +905,6 @@ dependencies = [ "serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-bidi" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-segmentation" version = "1.1.0" @@ -1493,11 +915,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unreachable" version = "0.1.1" @@ -1506,29 +923,6 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "url" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "user32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1554,119 +948,48 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a" -"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bufstream 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b48dbe2ff0e98fa2f03377d204a9637d3c9816cd431bfe05a8abbd0ea11d074" -"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" "checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758" "checksum cmake 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "e1acc68a3f714627af38f9f5d09706a28584ba60dfe2cca68f40bf779f941b25" -"checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" -"checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" -"checksum curl-sys 0.3.10 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d909dc402ae80b6f7b0118c039203436061b9d9a3ca5d2c2546d93e0a61aaa" -"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" -"checksum env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "99971fb1b635fe7a0ee3c4d065845bb93cca80a23b5613b5613391ece5de4144" +"checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum flate2 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "d4e4d0c15ef829cbc1b7cda651746be19cceeb238be7b1049227b14891df9e25" -"checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" -"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" "checksum gcc 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "c07c758b972368e703a562686adb39125707cc1ef3399da8c019fc6c2498a75d" -"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2" -"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 hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" -"checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6abe0ee2e758cd6bc8a2cd56726359007748fbf4128da998b65d0b70f881e19b" "checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" -"checksum libgit2-sys 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d951fd5eccae07c74e8c2c1075b05ea1e43be7f8952245af8c2840d1480b1d95" -"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934" -"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" -"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" -"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" +"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum mdbook 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dbba458ca886cb082d026afd704eeeeb0531f7e4ffd6c619f72dc309c1c18fe4" -"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 miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579" -"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2" -"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120" -"checksum num-bigint 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "88b14378471f7c2adc5262f05b4701ef53e8da376453a8d8fee48e51db745e49" -"checksum num-complex 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c78e054dd19c3fd03419ade63fa661e9c49bb890ce3beb4eee5b7baf93f92f" -"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92" -"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c" -"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf" "checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" -"checksum num_cpus 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a225d1e2717567599c24f88e49f00856c6e825a12125181ee42c4257e3688d39" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" -"checksum openssl 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f9871ecf7629da3760599e3e547d35940cff3cead49159b49f81cd1250f24f1d" -"checksum openssl-probe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "756d49c8424483a3df3b5d735112b4da22109ced9a8294f1f5cdf80fb3810919" -"checksum openssl-sys 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5dd48381e9e8a6dce9c4c402db143b2e243f5f872354532f7a009c289b3998ca" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" -"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" -"checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" -"checksum quote 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7375cf7ad34a92e8fd18dd9c42f58b9a11def59ab48bec955bf359a788335592" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" -"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" -"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" -"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e0ed773960f90a78567fcfbe935284adf50c5d7cf119aa2cf43bb0b4afa69bb" -"checksum serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d52006899f910528a10631e5b727973fe668f3228109d1707ccf5bad5490b6e" -"checksum serde_derive 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "789ee9f3cd78c850948b94121020147f5220b47dafbf230d7098a93a58f726cf" -"checksum serde_ignored 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4b3f5576874721d14690657e9f0ed286e72a52be2f6fdc0cf2f024182bd8f64" "checksum serde_json 0.9.7 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb96d30e4e6f9fc52e08f51176d078b6f79b981dc3ed4134f7b850be9f446a8" -"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8" -"checksum synom 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27e31aa4b09b9f4cb12dff3c30ba503e17b1a624413d764d32dab76e3920e5bc" -"checksum tar 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb3bf6ec92843ca93f4fcfb5fc6dfe30534815b147885db4b5759b8e2ff7d52" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" -"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" -"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" "checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796" "checksum toml 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08272367dd2e766db3fa38f068067d17aa6a9dfd7259af24b3927db92f1e0c2f" -"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" -"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" "checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" -"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" -"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" -"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/src/Cargo.toml b/src/Cargo.toml index c5ca80accbf02..0dafbb8428e3e 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -13,7 +13,6 @@ members = [ "tools/build-manifest", "tools/qemu-test-client", "tools/qemu-test-server", - "tools/cargo", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a996240f61650..5e6f3e9e6cc0f 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -79,6 +79,7 @@ fn main() { cmd.args(&args) .arg("--cfg") .arg(format!("stage{}", stage)) + .arg("--cfg").arg("rustbuild") .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 7dd53f41a214a..b326f95e505fb 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -296,8 +296,10 @@ def get_toml(self, key): def get_mk(self, key): for line in iter(self.config_mk.splitlines()): - if line.startswith(key): - return line[line.find(':=') + 2:].strip() + if line.startswith(key + ' '): + var = line[line.find(':=') + 2:].strip() + if var != '': + return var return None def cargo(self): @@ -438,6 +440,8 @@ def build_triple(self): sys.exit(err) elif ostype == 'Darwin': ostype = 'apple-darwin' + elif ostype == 'Haiku': + ostype = 'unknown-haiku' elif ostype.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: @@ -465,9 +469,12 @@ def build_triple(self): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype == 'armv7l': + elif cputype in {'armv6l', 'armv7l', 'armv8l'}: cputype = 'arm' ostype += 'eabihf' + elif cputype == 'armv7l': + cputype = 'armv7' + ostype += 'eabihf' elif cputype == 'aarch64': cputype = 'aarch64' elif cputype == 'arm64': @@ -488,12 +495,20 @@ def build_triple(self): raise ValueError('unknown byteorder: ' + sys.byteorder) # only the n64 ABI is supported, indicate it ostype += 'abi64' - elif cputype in {'powerpc', 'ppc', 'ppc64'}: + elif cputype in {'powerpc', 'ppc'}: cputype = 'powerpc' + elif cputype in {'powerpc64', 'ppc64'}: + cputype = 'powerpc64' + elif cputype in {'powerpc64le', 'ppc64le'}: + cputype = 'powerpc64le' elif cputype == 'sparcv9': pass elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}: cputype = 'x86_64' + elif cputype == 's390x': + cputype = 's390x' + elif cputype == 'BePC': + cputype = 'i686' else: err = "unknown cpu type: " + cputype if self.verbose: diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index dfe96b51799c0..68b3623a53f25 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -550,7 +550,7 @@ fn find_tests(dir: &Path, let filename = e.file_name().into_string().unwrap(); if (target.contains("windows") && filename.ends_with(".exe")) || (!target.contains("windows") && !filename.contains(".")) || - (target.contains("emscripten") && filename.contains(".js")){ + (target.contains("emscripten") && filename.ends_with(".js")) { dst.push(e.path()); } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 46d8d4b4aab2d..3459c1d2b8425 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -417,7 +417,10 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); - let dir = build.src.join("src/tools").join(tool); + let mut dir = build.src.join(tool); + if !dir.exists() { + dir = build.src.join("src/tools").join(tool); + } cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); // We don't want to build tools dynamically as they'll be running across diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 438ce6103d624..5e9ff98c4f25b 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -59,6 +59,8 @@ pub struct Config { pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, pub llvm_targets: Option, + pub llvm_link_jobs: Option, + pub llvm_clean_rebuild: bool, // rust codegen options pub rust_optimize: bool, @@ -179,6 +181,8 @@ struct Llvm { version_check: Option, static_libstdcpp: Option, targets: Option, + link_jobs: Option, + clean_rebuild: Option, } #[derive(RustcDecodable, Default, Clone)] @@ -332,7 +336,9 @@ impl Config { set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo); set(&mut config.llvm_version_check, llvm.version_check); set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp); + set(&mut config.llvm_clean_rebuild, llvm.clean_rebuild); config.llvm_targets = llvm.targets.clone(); + config.llvm_link_jobs = llvm.link_jobs; } if let Some(ref rust) = toml.rust { @@ -436,6 +442,7 @@ impl Config { ("LLVM_VERSION_CHECK", self.llvm_version_check), ("LLVM_STATIC_STDCPP", self.llvm_static_stdcpp), ("LLVM_LINK_SHARED", self.llvm_link_shared), + ("LLVM_CLEAN_REBUILD", self.llvm_clean_rebuild), ("OPTIMIZE", self.rust_optimize), ("DEBUG_ASSERTIONS", self.rust_debug_assertions), ("DEBUGINFO", self.rust_debuginfo), @@ -460,12 +467,12 @@ impl Config { } match key { - "CFG_BUILD" => self.build = value.to_string(), - "CFG_HOST" => { + "CFG_BUILD" if value.len() > 0 => self.build = value.to_string(), + "CFG_HOST" if value.len() > 0 => { self.host = value.split(" ").map(|s| s.to_string()) .collect(); } - "CFG_TARGET" => { + "CFG_TARGET" if value.len() > 0 => { self.target = value.split(" ").map(|s| s.to_string()) .collect(); } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 30763e38a336f..5a00e90f370b5 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -53,6 +53,19 @@ # Rust team and file an issue if you need assistance in porting! #targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +# Cap the number of parallel linker invocations when compiling LLVM. +# This can be useful when building LLVM with debug info, which significantly +# increases the size of binaries and consequently the memory required by +# each linker process. +# If absent or 0, linker invocations are treated like any other job and +# controlled by rustbuild's -j parameter. +#link-jobs = 0 + +# Delete LLVM build directory on LLVM rebuild. +# This option defaults to `false` for local development, but CI may want to +# always perform clean full builds (possibly accelerated by (s)ccache). +#clean-rebuild = false + # ============================================================================= # General build configuration options # ============================================================================= diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 67e4dad83ce88..d437e907d1e6c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -392,6 +392,7 @@ pub fn rust_src(build: &Build) { let src_dirs = [ "man", "src", + "cargo", ]; let filter_fn = move |path: &Path| { diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d19e5b1b88456..9c3f0ce62f349 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -19,10 +19,12 @@ use std::fs::{self, File}; use std::io::prelude::*; +use std::io; +use std::path::Path; use std::process::Command; use {Build, Compiler, Mode}; -use util::cp_r; +use util::{cp_r, symlink_dir}; use build_helper::up_to_date; /// Invoke `rustbook` as compiled in `stage` for `target` for the doc book @@ -141,7 +143,22 @@ pub fn std(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // Here what we're doing is creating a *symlink* (directory junction on + // Windows) to the final output location. This is not done as an + // optimization but rather for correctness. We've got three trees of + // documentation, one for std, one for test, and one for rustc. It's then + // our job to merge them all together. + // + // Unfortunately rustbuild doesn't know nearly as well how to merge doc + // trees as rustdoc does itself, so instead of actually having three + // separate trees we just have rustdoc output to the same location across + // all of them. + // + // This way rustdoc generates output directly into the output, and rustdoc + // will also directly handle merging. + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc"); cargo.arg("--manifest-path") @@ -166,7 +183,7 @@ pub fn std(build: &Build, stage: u32, target: &str) { build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Compile all libtest documentation. @@ -187,13 +204,16 @@ pub fn test(build: &Build, stage: u32, target: &str) { .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - build.clear_if_dirty(&out_dir, &rustdoc); + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); let mut cargo = build.cargo(&compiler, Mode::Libtest, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/libtest/Cargo.toml")); build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generate all compiler documentation. @@ -213,15 +233,28 @@ pub fn rustc(build: &Build, stage: u32, target: &str) { let out_dir = build.stage_out(&compiler, Mode::Librustc) .join(target).join("doc"); let rustdoc = build.rustdoc(&compiler); - if !up_to_date(&rustdoc, &out_dir.join("rustc/index.html")) && out_dir.exists() { - t!(fs::remove_dir_all(&out_dir)); - } + + // See docs in std above for why we symlink + let my_out = build.crate_doc_out(target); + build.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&my_out, &out_dir)); + let mut cargo = build.cargo(&compiler, Mode::Librustc, target, "doc"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/Cargo.toml")) .arg("--features").arg(build.rustc_features()); + + // Like with libstd above if compiler docs aren't enabled then we're not + // documenting internal dependencies, so we have a whitelist. + if !build.config.compiler_docs { + cargo.arg("--no-deps"); + for krate in &["proc_macro"] { + cargo.arg("-p").arg(krate); + } + } + build.run(&mut cargo); - cp_r(&out_dir, &out) + cp_r(&my_out, &out); } /// Generates the HTML rendered error-index by running the @@ -240,3 +273,15 @@ pub fn error_index(build: &Build, target: &str) { build.run(&mut index); } + +fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { + if let Ok(m) = fs::symlink_metadata(dst) { + if m.file_type().is_dir() { + try!(fs::remove_dir_all(dst)); + } else { + try!(fs::remove_file(dst)); + } + } + + symlink_dir(src, dst) +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 071d0b0b09009..97fc5886478c8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -707,6 +707,13 @@ impl Build { self.out.join(target).join("doc") } + /// Output directory for all crate documentation for a target (temporary) + /// + /// The artifacts here are then copied into `doc_out` above. + fn crate_doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("crate-docs") + } + /// Returns true if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 483f45fdd6218..6cc1ca8d02ed0 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -41,9 +41,9 @@ pub fn llvm(build: &Build, target: &str) { } } - let clean_trigger = build.src.join("src/rustllvm/llvm-auto-clean-trigger"); - let mut clean_trigger_contents = String::new(); - t!(t!(File::open(&clean_trigger)).read_to_string(&mut clean_trigger_contents)); + let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger"); + let mut rebuild_trigger_contents = String::new(); + t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); let out_dir = build.llvm_out(target); let done_stamp = out_dir.join("llvm-finished-building"); @@ -51,18 +51,15 @@ pub fn llvm(build: &Build, target: &str) { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); - // LLVM was already built previously. - // We don't track changes in LLVM sources, so we need to choose between reusing - // what was built previously, or cleaning the directory and doing a fresh build. - // The choice depends on contents of the clean-trigger file. - // If the contents are the same as during the previous build, then no action is required. - // If the contents differ from the previous build, then cleaning is triggered. - if done_contents == clean_trigger_contents { + // If LLVM was already built previously and contents of the rebuild-trigger file + // didn't change from the previous build, then no action is required. + if done_contents == rebuild_trigger_contents { return - } else { - t!(fs::remove_dir_all(&out_dir)); } } + if build.config.llvm_clean_rebuild { + drop(fs::remove_dir_all(&out_dir)); + } println!("Building LLVM for {}", target); let _time = util::timeit(); @@ -115,6 +112,12 @@ pub fn llvm(build: &Build, target: &str) { cfg.define("LLVM_BUILD_32_BITS", "ON"); } + if let Some(num_linkers) = build.config.llvm_link_jobs { + if num_linkers > 0 { + cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); + } + } + // http://llvm.org/docs/HowToCrossCompileLLVM.html if target != build.config.build { // FIXME: if the llvm root for the build triple is overridden then we @@ -148,7 +151,7 @@ pub fn llvm(build: &Build, target: &str) { // tools and libs on all platforms. cfg.build(); - t!(t!(File::create(&done_stamp)).write_all(clean_trigger_contents.as_bytes())); + t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes())); } fn check_llvm_version(build: &Build, llvm_config: &Path) { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index a5c0d11d21985..39f07459d4267 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -559,7 +559,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") .dep(|s| s.name("libstd")) .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); - rules.build("tool-cargo", "src/tools/cargo") + rules.build("tool-cargo", "cargo") .dep(|s| s.name("libstd")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { @@ -640,7 +640,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.doc(&krate.doc_step, path) .dep(|s| s.name("librustc-link")) .host(true) - .default(default && build.config.compiler_docs) + .default(default && build.config.docs) .run(move |s| doc::rustc(build, s.stage, s.target)); } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 520514f5fc95a..dab20f44bc361 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -16,10 +16,13 @@ use std::env; use std::ffi::OsString; use std::fs; +use std::io; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::Instant; +use filetime::{self, FileTime}; + /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { if target.contains("windows") { @@ -38,12 +41,18 @@ pub fn copy(src: &Path, dst: &Path) { // Attempt to "easy copy" by creating a hard link (symlinks don't work on // windows), but if that fails just fall back to a slow `copy` operation. - let res = fs::hard_link(src, dst); - let res = res.or_else(|_| fs::copy(src, dst).map(|_| ())); + // let res = fs::hard_link(src, dst); + let res = fs::copy(src, dst); if let Err(e) = res { panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e) } + let metadata = t!(src.metadata()); + t!(fs::set_permissions(dst, metadata.permissions())); + let atime = FileTime::from_last_access_time(&metadata); + let mtime = FileTime::from_last_modification_time(&metadata); + t!(filetime::set_file_times(dst, atime, mtime)); + } /// Copies the `src` directory recursively to `dst`. Both are assumed to exist @@ -175,3 +184,141 @@ impl Drop for TimeIt { time.subsec_nanos() / 1_000_000); } } + +/// Symlinks two directories, using junctions on Windows and normal symlinks on +/// Unix. +pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> { + let _ = fs::remove_dir(dest); + return symlink_dir_inner(src, dest); + + #[cfg(not(windows))] + fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> { + use std::os::unix::fs; + fs::symlink(src, dest) + } + + // Creating a directory junction on windows involves dealing with reparse + // points and the DeviceIoControl function, and this code is a skeleton of + // what can be found here: + // + // http://www.flexhex.com/docs/articles/hard-links.phtml + // + // Copied from std + #[cfg(windows)] + #[allow(bad_style)] + fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> { + use std::ptr; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; + const GENERIC_WRITE: DWORD = 0x40000000; + const OPEN_EXISTING: DWORD = 3; + const FILE_FLAG_OPEN_REPARSE_POINT: DWORD = 0x00200000; + const FILE_FLAG_BACKUP_SEMANTICS: DWORD = 0x02000000; + const FSCTL_SET_REPARSE_POINT: DWORD = 0x900a4; + const IO_REPARSE_TAG_MOUNT_POINT: DWORD = 0xa0000003; + const FILE_SHARE_DELETE: DWORD = 0x4; + const FILE_SHARE_READ: DWORD = 0x1; + const FILE_SHARE_WRITE: DWORD = 0x2; + + type BOOL = i32; + type DWORD = u32; + type HANDLE = *mut u8; + type LPCWSTR = *const u16; + type LPDWORD = *mut DWORD; + type LPOVERLAPPED = *mut u8; + type LPSECURITY_ATTRIBUTES = *mut u8; + type LPVOID = *mut u8; + type WCHAR = u16; + type WORD = u16; + + #[repr(C)] + struct REPARSE_MOUNTPOINT_DATA_BUFFER { + ReparseTag: DWORD, + ReparseDataLength: DWORD, + Reserved: WORD, + ReparseTargetLength: WORD, + ReparseTargetMaximumLength: WORD, + Reserved1: WORD, + ReparseTarget: WCHAR, + } + + extern "system" { + fn CreateFileW(lpFileName: LPCWSTR, + dwDesiredAccess: DWORD, + dwShareMode: DWORD, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + dwCreationDisposition: DWORD, + dwFlagsAndAttributes: DWORD, + hTemplateFile: HANDLE) + -> HANDLE; + fn DeviceIoControl(hDevice: HANDLE, + dwIoControlCode: DWORD, + lpInBuffer: LPVOID, + nInBufferSize: DWORD, + lpOutBuffer: LPVOID, + nOutBufferSize: DWORD, + lpBytesReturned: LPDWORD, + lpOverlapped: LPOVERLAPPED) -> BOOL; + } + + fn to_u16s>(s: S) -> io::Result> { + Ok(s.as_ref().encode_wide().chain(Some(0)).collect()) + } + + // We're using low-level APIs to create the junction, and these are more + // picky about paths. For example, forward slashes cannot be used as a + // path separator, so we should try to canonicalize the path first. + let target = try!(fs::canonicalize(target)); + + try!(fs::create_dir(junction)); + + let path = try!(to_u16s(junction)); + + unsafe { + let h = CreateFileW(path.as_ptr(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0 as *mut _, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + ptr::null_mut()); + + let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut db = data.as_mut_ptr() + as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; + let buf = &mut (*db).ReparseTarget as *mut _; + let mut i = 0; + // FIXME: this conversion is very hacky + let v = br"\??\"; + let v = v.iter().map(|x| *x as u16); + for c in v.chain(target.as_os_str().encode_wide().skip(4)) { + *buf.offset(i) = c; + i += 1; + } + *buf.offset(i) = 0; + i += 1; + (*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + (*db).ReparseTargetMaximumLength = (i * 2) as WORD; + (*db).ReparseTargetLength = ((i - 1) * 2) as WORD; + (*db).ReparseDataLength = + (*db).ReparseTargetLength as DWORD + 12; + + let mut ret = 0; + let res = DeviceIoControl(h as *mut _, + FSCTL_SET_REPARSE_POINT, + data.as_ptr() as *mut _, + (*db).ReparseDataLength + 8, + ptr::null_mut(), 0, + &mut ret, + ptr::null_mut()); + + if res == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + } +} diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 1e61f2169106c..437041e0292ca 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -30,13 +30,17 @@ retry docker \ objdir=$root_dir/obj mkdir -p $HOME/.cargo -mkdir -p $objdir +mkdir -p $objdir/tmp 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_ERROR_LOG=/tmp/sccache/sccache.log" + args="$args --env SCCACHE_LOG_LEVEL=debug" + args="$args --env RUST_LOG=sccache=debug" + args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache" diff --git a/src/ci/run.sh b/src/ci/run.sh index 4c4836d7ca230..19bea9ced0642 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -28,6 +28,7 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-locked-deps" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-cargo-openssl-static" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-clean-rebuild" if [ "$DIST_SRC" = "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src" diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d0fce70612868..43b0d72186a29 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -225,6 +225,8 @@ impl Drop for IntermediateBox { impl Box { /// Allocates memory on the heap and then places `x` into it. /// + /// This doesn't actually allocate if `T` is zero-sized. + /// /// # Examples /// /// ``` diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 8d42045ff1637..24f57c506304c 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -22,7 +22,7 @@ use core::cmp::Ordering; use core::fmt; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; -use core::ops::{Index, IndexMut}; +use core::ops::{Index, IndexMut, Place, Placer, InPlace}; use core::ptr; use core::ptr::Shared; use core::slice; @@ -1087,14 +1087,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_front(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); self.tail = self.wrap_sub(self.tail, 1); let tail = self.tail; @@ -1117,14 +1110,7 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push_back(&mut self, value: T) { - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); let head = self.head; self.head = self.wrap_add(self.head, 1); @@ -1257,14 +1243,7 @@ impl VecDeque { #[stable(feature = "deque_extras_15", since = "1.5.0")] pub fn insert(&mut self, index: usize, value: T) { assert!(index <= self.len(), "index out of bounds"); - if self.is_full() { - let old_cap = self.cap(); - self.buf.double(); - unsafe { - self.handle_cap_increase(old_cap); - } - debug_assert!(!self.is_full()); - } + self.grow_if_necessary(); // Move the least number of elements in the ring buffer and insert // the given object @@ -1762,6 +1741,69 @@ impl VecDeque { self.truncate(len - del); } } + + // This may panic or abort + #[inline] + fn grow_if_necessary(&mut self) { + if self.is_full() { + let old_cap = self.cap(); + self.buf.double(); + unsafe { + self.handle_cap_increase(old_cap); + } + debug_assert!(!self.is_full()); + } + } + + /// Returns a place for insertion at the back of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_back`](#method.push_back), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_back() <- 3; + /// buf.place_back() <- 4; + /// assert_eq!(&buf, &[3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack { + PlaceBack { vec_deque: self } + } + + /// Returns a place for insertion at the front of the `VecDeque`. + /// + /// Using this method with placement syntax is equivalent to [`push_front`](#method.push_front), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.place_front() <- 3; + /// buf.place_front() <- 4; + /// assert_eq!(&buf, &[4, 3]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_front(&mut self) -> PlaceFront { + PlaceFront { vec_deque: self } + } } impl VecDeque { @@ -2442,6 +2484,98 @@ impl From> for Vec { } } +/// A place for insertion at the back of a `VecDeque`. +/// +/// See [`VecDeque::place_back`](struct.VecDeque.html#method.place_back) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceBack<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceBack<'a, T> { + type Place = PlaceBack<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceBack<'a, T> { + fn pointer(&mut self) -> *mut T { + unsafe { self.vec_deque.ptr().offset(self.vec_deque.head as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceBack<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + let head = self.vec_deque.head; + self.vec_deque.head = self.vec_deque.wrap_add(head, 1); + &mut *(self.vec_deque.ptr().offset(head as isize)) + } +} + +/// A place for insertion at the front of a `VecDeque`. +/// +/// See [`VecDeque::place_front`](struct.VecDeque.html#method.place_front) for details. +#[must_use = "places do nothing unless written to with `<-` syntax"] +#[unstable(feature = "collection_placement", + reason = "struct name and placement protocol are subject to change", + issue = "30172")] +#[derive(Debug)] +pub struct PlaceFront<'a, T: 'a> { + vec_deque: &'a mut VecDeque, +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Placer for PlaceFront<'a, T> { + type Place = PlaceFront<'a, T>; + + fn make_place(self) -> Self { + self.vec_deque.grow_if_necessary(); + self + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> Place for PlaceFront<'a, T> { + fn pointer(&mut self) -> *mut T { + let tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + unsafe { self.vec_deque.ptr().offset(tail as isize) } + } +} + +#[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] +impl<'a, T> InPlace for PlaceFront<'a, T> { + type Owner = &'a mut T; + + unsafe fn finalize(mut self) -> &'a mut T { + self.vec_deque.tail = self.vec_deque.wrap_sub(self.vec_deque.tail, 1); + &mut *(self.vec_deque.ptr().offset(self.vec_deque.tail as isize)) + } +} + #[cfg(test)] mod tests { use test; @@ -2797,4 +2931,5 @@ mod tests { } } } + } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 849d240169169..d97d9b8ab83f6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -32,6 +32,7 @@ extern crate collections; extern crate test; extern crate std_unicode; +extern crate core; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs index 1541061a19842..f2935c05d4f7a 100644 --- a/src/libcollectionstest/vec_deque.rs +++ b/src/libcollectionstest/vec_deque.rs @@ -10,7 +10,7 @@ use std::collections::VecDeque; use std::fmt::Debug; -use std::collections::vec_deque::Drain; +use std::collections::vec_deque::{Drain}; use self::Taggy::*; use self::Taggypar::*; @@ -1000,3 +1000,25 @@ fn test_is_empty() { assert!(v.iter_mut().is_empty()); assert!(v.into_iter().is_empty()); } + +#[test] +fn test_placement_in() { + let mut buf: VecDeque = VecDeque::new(); + buf.place_back() <- 1; + buf.place_back() <- 2; + assert_eq!(buf, [1,2]); + + buf.place_front() <- 3; + buf.place_front() <- 4; + assert_eq!(buf, [4,3,1,2]); + + { + let ptr_head = buf.place_front() <- 5; + assert_eq!(*ptr_head, 5); + } + { + let ptr_tail = buf.place_back() <- 6; + assert_eq!(*ptr_tail, 6); + } + assert_eq!(buf, [5,4,3,1,2,6]); +} diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d034..0000000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135ef..0000000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c7257..0000000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc8b..0000000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 8d7fe655c23b2..0d2a467b57702 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -21,7 +21,7 @@ //! This functionality is intended to be expanded over time as more surface //! area for macro authors is stabilized. //! -//! See [the book](../../book/procedural-macros.html) for more. +//! See [the book](../book/procedural-macros.html) for more. #![crate_name = "proc_macro"] #![stable(feature = "proc_macro_lib", since = "1.15.0")] diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7fdc..fa217acd9f9bf 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index e6736ccafbad9..8be5d4327e72e 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -18,6 +18,7 @@ use std::sync::Arc; use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; use super::raii; +use super::safe::DepGraphSafe; use super::thread::{DepGraphThreadData, DepMessage}; #[derive(Clone)] @@ -76,11 +77,38 @@ impl DepGraph { op() } - pub fn with_task(&self, key: DepNode, op: OP) -> R - where OP: FnOnce() -> R + /// Starts a new dep-graph task. Dep-graph tasks are specified + /// using a free function (`task`) and **not** a closure -- this + /// is intentional because we want to exercise tight control over + /// what state they have access to. In particular, we want to + /// prevent implicit 'leaks' of tracked state into the task (which + /// could then be read without generating correct edges in the + /// dep-graph -- see the [README] for more details on the + /// dep-graph). To this end, the task function gets exactly two + /// pieces of state: the context `cx` and an argument `arg`. Both + /// of these bits of state must be of some type that implements + /// `DepGraphSafe` and hence does not leak. + /// + /// The choice of two arguments is not fundamental. One argument + /// would work just as well, since multiple values can be + /// collected using tuples. However, using two arguments works out + /// to be quite convenient, since it is common to need a context + /// (`cx`) and some argument (e.g., a `DefId` identifying what + /// item to process). + /// + /// For cases where you need some other number of arguments: + /// + /// - If you only need one argument, just use `()` for the `arg` + /// parameter. + /// - If you need 3+ arguments, use a tuple for the + /// `arg` parameter. + /// + /// [README]: README.md + pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); - op() + task(cx, arg) } pub fn read(&self, v: DepNode) { diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 7331756f35b8e..a9f0a44e4208c 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,7 @@ mod edges; mod graph; mod query; mod raii; +mod safe; mod shadow; mod thread; mod visit; @@ -25,6 +26,8 @@ pub use self::dep_node::WorkProductId; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; +pub use self::safe::AssertDepGraphSafe; +pub use self::safe::DepGraphSafe; pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs new file mode 100644 index 0000000000000..f85f0338ed997 --- /dev/null +++ b/src/librustc/dep_graph/safe.rs @@ -0,0 +1,63 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir::BodyId; +use hir::def_id::DefId; +use syntax::ast::NodeId; +use ty::TyCtxt; + +/// The `DepGraphSafe` trait is used to specify what kinds of values +/// are safe to "leak" into a task. The idea is that this should be +/// only be implemented for things like the tcx as well as various id +/// types, which will create reads in the dep-graph whenever the trait +/// loads anything that might depend on the input program. +pub trait DepGraphSafe { +} + +/// A `BodyId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for BodyId { +} + +/// A `NodeId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for NodeId { +} + +/// A `DefId` on its own doesn't give access to any particular state. +/// You must fetch the state from the various maps or generate +/// on-demand queries, all of which create reads. +impl DepGraphSafe for DefId { +} + +/// The type context itself can be used to access all kinds of tracked +/// state, but those accesses should always generate read events. +impl<'a, 'gcx, 'tcx> DepGraphSafe for TyCtxt<'a, 'gcx, 'tcx> { +} + +/// Tuples make it easy to build up state. +impl DepGraphSafe for (A, B) + where A: DepGraphSafe, B: DepGraphSafe +{ +} + +/// No data here! :) +impl DepGraphSafe for () { +} + +/// A convenient override that lets you pass arbitrary state into a +/// task. Every use should be accompanied by a comment explaining why +/// it makes sense (or how it could be refactored away in the future). +pub struct AssertDepGraphSafe(pub T); + +impl DepGraphSafe for AssertDepGraphSafe { +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 257cdb960d529..c16107949b615 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -79,10 +79,12 @@ pub struct LoweringContext<'a> { trait_items: BTreeMap, impl_items: BTreeMap, bodies: BTreeMap, + exported_macros: Vec, trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -121,6 +123,8 @@ pub fn lower_crate(sess: &Session, bodies: BTreeMap::new(), trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), + catch_scopes: Vec::new(), + exported_macros: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -170,9 +174,10 @@ impl<'a> LoweringContext<'a> { impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { fn visit_item(&mut self, item: &'lcx Item) { - let hir_item = self.lctx.lower_item(item); - self.lctx.items.insert(item.id, hir_item); - visit::walk_item(self, item); + if let Some(hir_item) = self.lctx.lower_item(item) { + self.lctx.items.insert(item.id, hir_item); + visit::walk_item(self, item); + } } fn visit_trait_item(&mut self, item: &'lcx TraitItem) { @@ -195,14 +200,13 @@ impl<'a> LoweringContext<'a> { let module = self.lower_mod(&c.module); let attrs = self.lower_attrs(&c.attrs); - let exported_macros = c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(); let body_ids = body_ids(&self.bodies); hir::Crate { module: module, attrs: attrs, span: c.span, - exported_macros: exported_macros, + exported_macros: hir::HirVec::from(self.exported_macros), items: self.items, trait_items: self.trait_items, impl_items: self.impl_items, @@ -259,6 +263,21 @@ impl<'a> LoweringContext<'a> { span } + fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.catch_scopes.len(); + self.catch_scopes.push(catch_id); + + let result = f(self); + assert_eq!(len + 1, self.catch_scopes.len(), + "catch scopes should be added and removed in stack order"); + + self.catch_scopes.pop().unwrap(); + + result + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -293,15 +312,17 @@ impl<'a> LoweringContext<'a> { result } - fn with_new_loop_scopes(&mut self, f: F) -> T + fn with_new_scopes(&mut self, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); let result = f(self); - mem::replace(&mut self.loop_scopes, loop_scopes); + self.catch_scopes = catch_scopes; + self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; @@ -1063,7 +1084,7 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { let body = this.lower_block(body); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); @@ -1134,7 +1155,7 @@ impl<'a> LoweringContext<'a> { bounds, items) } - ItemKind::Mac(_) => panic!("Shouldn't still be around"), + ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } } @@ -1256,42 +1277,45 @@ impl<'a> LoweringContext<'a> { } } - fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef { - hir::MacroDef { - name: m.ident.name, - attrs: self.lower_attrs(&m.attrs), - id: m.id, - span: m.span, - body: m.body.clone().into(), - } - } - fn lower_item_id(&mut self, i: &Item) -> SmallVector { - if let ItemKind::Use(ref view_path) = i.node { - if let ViewPathList(_, ref imports) = view_path.node { - return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) - .map(|id| hir::ItemId { id: id }).collect(); + match i.node { + ItemKind::Use(ref view_path) => { + if let ViewPathList(_, ref imports) = view_path.node { + return iter::once(i.id).chain(imports.iter().map(|import| import.node.id)) + .map(|id| hir::ItemId { id: id }).collect(); + } } + ItemKind::MacroDef(..) => return SmallVector::new(), + _ => {} } SmallVector::one(hir::ItemId { id: i.id }) } - pub fn lower_item(&mut self, i: &Item) -> hir::Item { + pub fn lower_item(&mut self, i: &Item) -> Option { let mut name = i.ident.name; let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); + if let ItemKind::MacroDef(ref tts) = i.node { + if i.attrs.iter().any(|attr| attr.name() == "macro_export") { + self.exported_macros.push(hir::MacroDef { + name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), + }); + } + return None; + } + let node = self.with_parent_def(i.id, |this| { this.lower_item_kind(i.id, &mut name, &attrs, &mut vis, &i.node) }); - hir::Item { + Some(hir::Item { id: i.id, name: name, attrs: attrs, node: node, vis: vis, span: i.span, - } + }) } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { @@ -1660,13 +1684,17 @@ impl<'a> LoweringContext<'a> { this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } + ExprKind::Catch(ref body) => { + // FIXME(cramertj): Add catch to HIR + self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let expr = this.lower_expr(body); hir::ExprClosure(this.lower_capture_clause(capture_clause), @@ -2064,6 +2092,12 @@ impl<'a> LoweringContext<'a> { // Err(err) => #[allow(unreachable_code)] // return Carrier::from_error(From::from(err)), // } + + // FIXME(cramertj): implement breaking to catch + if !self.catch_scopes.is_empty() { + bug!("`?` in catch scopes is unimplemented") + } + let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index ccaf663c7ad2a..f15e063e81e33 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -108,7 +108,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::Mac(..) if i.id == DUMMY_NODE_ID => return, // Scope placeholder + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::Use(ref view_path) => { match view_path.node { @@ -269,10 +269,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name.as_str())); } - fn visit_macro_def(&mut self, macro_def: &'a MacroDef) { - self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.ident.name.as_str())); - } - fn visit_stmt(&mut self, stmt: &'a Stmt) { match stmt.node { StmtKind::Mac(..) => self.visit_macro_invoc(stmt.id, false), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5d074903b2b99..2a938dadd28dc 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -948,7 +948,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index c835189820e51..68e64b8b7bfc8 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -152,7 +152,7 @@ course, it depends on the program. The main case which fails today that I would like to support is: -```text +```rust fn foo(x: T, y: T) { ... } fn bar() { @@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for `X`, and thus inherits its UB/LB of `@mut int`. This leaves no flexibility for `T` to later adjust to accommodate `@int`. +Note: `@` and `@mut` are replaced with `Rc` and `Rc>` in current Rust. + ### What to do when not all bounds are present In the prior discussion we assumed that A.ub was not top and B.lb was diff --git a/src/librustc/infer/region_inference/README.md b/src/librustc/infer/region_inference/README.md index 80da861139b42..b564faf3d0c24 100644 --- a/src/librustc/infer/region_inference/README.md +++ b/src/librustc/infer/region_inference/README.md @@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to "execute" by testing the value they are applied to and creating any relevant bindings). So, for example: - fn foo(x: isize, y: isize) { // -+ - // +------------+ // | - // | +-----+ // | - // | +-+ +-+ +-+ // | - // | | | | | | | // | - // v v v v v v v // | - let z = x + y; // | - ... // | - } // -+ - - fn bar() { ... } +```rust +fn foo(x: isize, y: isize) { // -+ +// +------------+ // | +// | +-----+ // | +// | +-+ +-+ +-+ // | +// | | | | | | | // | +// v v v v v v v // | + let z = x + y; // | + ... // | +} // -+ + +fn bar() { ... } +``` In this example, there is a region for the fn body block as a whole, and then a subregion for the declaration of the local variable. @@ -160,7 +162,9 @@ this, we get a lot of spurious errors around nested calls, in particular when combined with `&mut` functions. For example, a call like this one - self.foo(self.bar()) +```rust +self.foo(self.bar()) +``` where both `foo` and `bar` are `&mut self` functions will always yield an error. @@ -168,20 +172,22 @@ an error. Here is a more involved example (which is safe) so we can see what's going on: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn inc(p: &mut usize) -> usize { - *p += 1; *p - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, - 'b: inc(&mut (*x).f)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn inc(p: &mut usize) -> usize { + *p += 1; *p +} +fn weird() { + let mut x: Box = box Foo { /* ... */ }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (..) +} +``` The important part is the line marked `(..)` which contains a call to `add()`. The first argument is a mutable borrow of the field `f`. The @@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes involved with `'a` in detail. We'll break apart all the steps involved in a call expression: - 'a: { - 'a_arg1: let a_temp1: ... = add; - 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; - 'a_arg3: let a_temp3: usize = { - let b_temp1: ... = inc; - let b_temp2: &'b = &'b mut (*x).f; - 'b_call: b_temp1(b_temp2) - }; - 'a_call: a_temp1(a_temp2, a_temp3) // (**) - } +```rust +'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; + 'a_arg3: let a_temp3: usize = { + let b_temp1: ... = inc; + let b_temp2: &'b = &'b mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) // (**) +} +``` Here we see that the lifetime `'a` includes a number of substatements. In particular, there is this lifetime I've called `'a_call` that @@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second argument, it can still be *invalidated* by that evaluation. Consider this similar but unsound example: - struct Foo { f: usize, g: usize } - ... - fn add(p: &mut usize, v: usize) { - *p += v; - } - ... - fn consume(x: Box) -> usize { - x.f + x.g - } - fn weird() { - let mut x: Box = box Foo { ... }; - 'a: add(&mut (*x).f, consume(x)) // (..) - } +```rust +struct Foo { f: usize, g: usize } +// ... +fn add(p: &mut usize, v: usize) { + *p += v; +} +// ... +fn consume(x: Box) -> usize { + x.f + x.g +} +fn weird() { + let mut x: Box = box Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (..) +} +``` In this case, the second argument to `add` actually consumes `x`, thus invalidating the first argument. diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 95ce8d39ff488..a67049f72852b 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( }; if output_template.is_empty() { - bug!("empty string provided as RUST_REGION_GRAPH"); + panic!("empty string provided as RUST_REGION_GRAPH"); } if output_template.contains('%') { diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 32bc81e947037..9279f24a57ab3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -806,6 +806,12 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.tables = old_tables; } + fn visit_body(&mut self, body: &'tcx hir::Body) { + run_lints!(self, check_body, late_passes, body); + hir_visit::walk_body(self, body); + run_lints!(self, check_body_post, late_passes, body); + } + fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { run_lints!(cx, check_item, late_passes, it); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e9f603db15d62..e81d09773701c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -133,6 +133,8 @@ pub trait LintPass { // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. pub trait LateLintPass<'a, 'tcx>: LintPass { + fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { } + fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { } fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4a7027b8997a5..e9fb4632fa178 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -136,7 +136,7 @@ pub struct NativeLibrary { } pub enum LoadedMacro { - MacroRules(ast::MacroDef), + MacroDef(ast::Item), ProcMacro(Rc), } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index ed72fe1801663..fea576f706780 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -19,6 +19,7 @@ use hir::def::CtorKind; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use util::ppaux; use rustc_back::slice; use hir::InlineAsm; @@ -63,8 +64,7 @@ macro_rules! newtype_index { } /// Lowered representation of a single function. -// Do not implement clone for Mir, which can be accidently done and kind of expensive. -#[derive(RustcEncodable, RustcDecodable, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Mir<'tcx> { /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` /// that indexes into this vector. @@ -1333,3 +1333,347 @@ impl Location { } } } + + +/* + * TypeFoldable implementations for MIR types + */ + +impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Mir { + basic_blocks: self.basic_blocks.fold_with(folder), + visibility_scopes: self.visibility_scopes.clone(), + promoted: self.promoted.fold_with(folder), + return_ty: self.return_ty.fold_with(folder), + local_decls: self.local_decls.fold_with(folder), + arg_count: self.arg_count, + upvar_decls: self.upvar_decls.clone(), + spread_arg: self.spread_arg, + span: self.span, + cache: cache::Cache::new() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.basic_blocks.visit_with(visitor) || + self.promoted.visit_with(visitor) || + self.return_ty.visit_with(visitor) || + self.local_decls.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + LocalDecl { + ty: self.ty.fold_with(folder), + ..self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + BasicBlockData { + statements: self.statements.fold_with(folder), + terminator: self.terminator.fold_with(folder), + is_cleanup: self.is_cleanup + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.statements.visit_with(visitor) || self.terminator.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::StatementKind::*; + + let kind = match self.kind { + Assign(ref lval, ref rval) => Assign(lval.fold_with(folder), rval.fold_with(folder)), + SetDiscriminant { ref lvalue, variant_index } => SetDiscriminant { + lvalue: lvalue.fold_with(folder), + variant_index: variant_index + }, + StorageLive(ref lval) => StorageLive(lval.fold_with(folder)), + StorageDead(ref lval) => StorageDead(lval.fold_with(folder)), + InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm { + asm: asm.clone(), + outputs: outputs.fold_with(folder), + inputs: inputs.fold_with(folder) + }, + Nop => Nop, + }; + Statement { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::StatementKind::*; + + match self.kind { + Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) } + SetDiscriminant { ref lvalue, .. } | + StorageLive(ref lvalue) | + StorageDead(ref lvalue) => lvalue.visit_with(visitor), + InlineAsm { ref outputs, ref inputs, .. } => + outputs.visit_with(visitor) || inputs.visit_with(visitor), + Nop => false, + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::TerminatorKind::*; + + let kind = match self.kind { + Goto { target } => Goto { target: target }, + SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + discr: discr.fold_with(folder), + switch_ty: switch_ty.fold_with(folder), + values: values.clone(), + targets: targets.clone() + }, + Drop { ref location, target, unwind } => Drop { + location: location.fold_with(folder), + target: target, + unwind: unwind + }, + DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { + location: location.fold_with(folder), + value: value.fold_with(folder), + target: target, + unwind: unwind + }, + Call { ref func, ref args, ref destination, cleanup } => { + let dest = destination.as_ref().map(|&(ref loc, dest)| { + (loc.fold_with(folder), dest) + }); + + Call { + func: func.fold_with(folder), + args: args.fold_with(folder), + destination: dest, + cleanup: cleanup + } + }, + Assert { ref cond, expected, ref msg, target, cleanup } => { + let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + AssertMessage::BoundsCheck { + len: len.fold_with(folder), + index: index.fold_with(folder), + } + } else { + msg.clone() + }; + Assert { + cond: cond.fold_with(folder), + expected: expected, + msg: msg, + target: target, + cleanup: cleanup + } + }, + Resume => Resume, + Return => Return, + Unreachable => Unreachable, + }; + Terminator { + source_info: self.source_info, + kind: kind + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::TerminatorKind::*; + + match self.kind { + SwitchInt { ref discr, switch_ty, .. } => + discr.visit_with(visitor) || switch_ty.visit_with(visitor), + Drop { ref location, ..} => location.visit_with(visitor), + DropAndReplace { ref location, ref value, ..} => + location.visit_with(visitor) || value.visit_with(visitor), + Call { ref func, ref args, ref destination, .. } => { + let dest = if let Some((ref loc, _)) = *destination { + loc.visit_with(visitor) + } else { false }; + dest || func.visit_with(visitor) || args.visit_with(visitor) + }, + Assert { ref cond, ref msg, .. } => { + if cond.visit_with(visitor) { + if let AssertMessage::BoundsCheck { ref len, ref index } = *msg { + len.visit_with(visitor) || index.visit_with(visitor) + } else { + false + } + } else { + false + } + }, + Goto { .. } | + Resume | + Return | + Unreachable => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Lvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match self { + &Lvalue::Projection(ref p) => Lvalue::Projection(p.fold_with(folder)), + _ => self.clone() + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + if let &Lvalue::Projection(ref p) = self { + p.visit_with(visitor) + } else { + false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::Rvalue::*; + match *self { + Use(ref op) => Use(op.fold_with(folder)), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Ref(region, bk, ref lval) => Ref(region.fold_with(folder), bk, lval.fold_with(folder)), + Len(ref lval) => Len(lval.fold_with(folder)), + Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), + BinaryOp(op, ref rhs, ref lhs) => + BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + CheckedBinaryOp(op, ref rhs, ref lhs) => + CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), + Discriminant(ref lval) => Discriminant(lval.fold_with(folder)), + Box(ty) => Box(ty.fold_with(folder)), + Aggregate(ref kind, ref fields) => { + let kind = match *kind { + AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), + AggregateKind::Tuple => AggregateKind::Tuple, + AggregateKind::Adt(def, v, substs, n) => + AggregateKind::Adt(def, v, substs.fold_with(folder), n), + AggregateKind::Closure(id, substs) => + AggregateKind::Closure(id, substs.fold_with(folder)) + }; + Aggregate(kind, fields.fold_with(folder)) + } + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + use mir::Rvalue::*; + match *self { + Use(ref op) => op.visit_with(visitor), + Repeat(ref op, _) => op.visit_with(visitor), + Ref(region, _, ref lval) => region.visit_with(visitor) || lval.visit_with(visitor), + Len(ref lval) => lval.visit_with(visitor), + Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), + BinaryOp(_, ref rhs, ref lhs) | + CheckedBinaryOp(_, ref rhs, ref lhs) => + rhs.visit_with(visitor) || lhs.visit_with(visitor), + UnaryOp(_, ref val) => val.visit_with(visitor), + Discriminant(ref lval) => lval.visit_with(visitor), + Box(ty) => ty.visit_with(visitor), + Aggregate(ref kind, ref fields) => { + (match *kind { + AggregateKind::Array(ty) => ty.visit_with(visitor), + AggregateKind::Tuple => false, + AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), + AggregateKind::Closure(_, substs) => substs.visit_with(visitor) + }) || fields.visit_with(visitor) + } + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)), + Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Operand::Consume(ref lval) => lval.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor) + } + } +} + +impl<'tcx, B, V> TypeFoldable<'tcx> for Projection<'tcx, B, V> + where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx> +{ + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + use mir::ProjectionElem::*; + + let base = self.base.fold_with(folder); + let elem = match self.elem { + Deref => Deref, + Field(f, ty) => Field(f, ty.fold_with(folder)), + Index(ref v) => Index(v.fold_with(folder)), + ref elem => elem.clone() + }; + + Projection { + base: base, + elem: elem + } + } + + fn super_visit_with>(&self, visitor: &mut Vs) -> bool { + use mir::ProjectionElem::*; + + self.base.visit_with(visitor) || + match self.elem { + Field(_, ty) => ty.visit_with(visitor), + Index(ref v) => v.visit_with(visitor), + _ => false + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + Constant { + span: self.span.clone(), + ty: self.ty.fold_with(folder), + literal: self.literal.fold_with(folder) + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.ty.visit_with(visitor) || self.literal.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + Literal::Item { def_id, substs } => Literal::Item { + def_id: def_id, + substs: substs.fold_with(folder) + }, + _ => self.clone() + } + } + fn super_visit_with>(&self, visitor: &mut V) -> bool { + match *self { + Literal::Item { substs, .. } => substs.visit_with(visitor), + _ => false + } + } +} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 99db5f9b62435..0e5c786cd8dcf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -23,11 +23,17 @@ use super::{ ObjectSafetyViolation, }; +use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; +use hir::{intravisit, Local, Pat}; +use hir::intravisit::{Visitor, NestedVisitorMap}; +use hir::map::NodeExpr; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; +use std::fmt; +use syntax::ast; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; @@ -35,12 +41,8 @@ use ty::fold::TypeFolder; use ty::subst::Subst; use util::nodemap::{FxHashMap, FxHashSet}; -use std::fmt; -use syntax::ast; -use hir::{intravisit, Local, Pat}; -use hir::intravisit::{Visitor, NestedVisitorMap}; use syntax_pos::{DUMMY_SP, Span}; -use errors::DiagnosticBuilder; + #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { @@ -848,15 +850,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); - let expr = self.tcx.hir.expect_expr(cause.body_id); - let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, found_pattern: None, }; - local_visitor.visit_expr(expr); + // #40294: cause.body_id can also be a fn declaration. + // Currently, if it's anything other than NodeExpr, we just ignore it + match self.tcx.hir.find(cause.body_id) { + Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), + _ => () + } if let Some(pattern) = local_visitor.found_pattern { let pattern_span = pattern.span; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 4c4ace0d8baf9..38ea1e4a19b91 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2461,7 +2461,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let new_trait = tcx.mk_dynamic( ty::Binder(tcx.mk_existential_predicates(iter)), r_b); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_trait, target) + self.infcx.eq_types(false, &obligation.cause, new_trait, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); @@ -2520,7 +2520,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // [T; n] -> [T]. (&ty::TyArray(a, _), &ty::TySlice(b)) => { let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, a, b) + self.infcx.eq_types(false, &obligation.cause, a, b) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); } @@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }); let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); let InferOk { obligations, .. } = - self.infcx.sub_types(false, &obligation.cause, new_struct, target) + self.infcx.eq_types(false, &obligation.cause, new_struct, target) .map_err(|_| Unimplemented)?; self.inferred_obligations.extend(obligations); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index be04b0e6577f0..3c37c7353d683 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2302,6 +2302,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { queries::mir::get(self, DUMMY_SP, did).borrow() } + /// Given the DefId of an item, returns its MIR, borrowed immutably. + /// Returns None if there is no MIR for the DefId + pub fn maybe_item_mir(self, did: DefId) -> Option>> { + if did.is_local() && !self.maps.mir.borrow().contains_key(&did) { + return None; + } + + if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) { + return None; + } + + Some(self.item_mir(did)) + } + /// If `type_needs_drop` returns true, then `ty` is definitely /// non-copy and *might* have a destructor attached; if it returns /// false, then `ty` definitely has no destructor (i.e. no drop glue). diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 48f6fcd11b8ac..49824e8a738d7 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -12,6 +12,7 @@ use infer::type_variable; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use std::rc::Rc; use syntax::abi; @@ -834,3 +835,13 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun self.expected.visit_with(visitor) || self.found.visit_with(visitor) } } + +impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + self.iter().map(|x| x.fold_with(folder)).collect() + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index be1582066e393..a81c3a177f885 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -654,11 +654,12 @@ impl<'a, 'tcx> ty::TyS<'tcx> { } tcx.layout_depth.set(depth+1); - let layout = Layout::compute_uncached(self, infcx)?; + let layout = Layout::compute_uncached(self, infcx); + tcx.layout_depth.set(depth); + let layout = layout?; if can_cache { tcx.layout_cache.borrow_mut().insert(self, layout); } - tcx.layout_depth.set(depth); Ok(layout) } diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a9f..730abc54568e1 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f176848..af99c0e938724 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 47b614a81ae25..b441a231874a6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -61,13 +61,16 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, || { + tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); + + fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { - tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), || { - borrowck_fn(tcx, body_id); - }); + tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), + tcx, + body_id, + borrowck_fn); }); - }); + } } /// Collection of conclusions determined via borrow checker analyses. diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32ec..907410f74dca4 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d9871..343b1ed68b804 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 00cea9cbdf6b7..3f478d7c165d1 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::range::RangeArgument; use std::fmt::Debug; use std::iter::{self, FromIterator}; use std::slice; @@ -145,6 +146,18 @@ impl IndexVec { self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) } + #[inline] + pub fn drain<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range) + } + + #[inline] + pub fn drain_enumerated<'a, R: RangeArgument>( + &'a mut self, range: R) -> impl Iterator + 'a { + self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + } + #[inline] pub fn last(&self) -> Option { self.len().checked_sub(1).map(I::new) @@ -164,6 +177,16 @@ impl IndexVec { pub fn truncate(&mut self, a: usize) { self.raw.truncate(a) } + + #[inline] + pub fn get(&self, index: I) -> Option<&T> { + self.raw.get(index.index()) + } + + #[inline] + pub fn get_mut(&mut self, index: I) -> Option<&mut T> { + self.raw.get_mut(index.index()) + } } impl Index for IndexVec { diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 3dce4398f3b91..f278325ebec74 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -38,6 +38,7 @@ #![feature(associated_consts)] #![feature(unsize)] #![feature(i128_type)] +#![feature(conservative_impl_trait)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e0058..5b5113caa8e8c 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 9619ba8472404..834240cb69797 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -43,7 +43,6 @@ use super::Compilation; use serialize::json; use std::env; -use std::mem; use std::ffi::{OsString, OsStr}; use std::fs; use std::io::{self, Write}; @@ -125,6 +124,10 @@ pub fn compile_input(sess: &Session, }; write_out_deps(sess, &outputs, &crate_name); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) && + sess.opts.output_types.keys().count() == 1 { + return Ok(()) + } let arena = DroplessArena::new(); let arenas = GlobalArenas::new(); @@ -195,13 +198,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } @@ -604,7 +607,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives(); let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, - llvm_passes, attributes, mir_passes, .. } = registry; + llvm_passes, attributes, .. } = registry; sess.track_errors(|| { let mut ls = sess.lint_store.borrow_mut(); @@ -620,7 +623,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, } *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; - sess.mir_passes.borrow_mut().extend(mir_passes); *sess.plugin_attributes.borrow_mut() = attributes.clone(); })?; @@ -705,8 +707,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate }); - krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); - krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, &mut resolver, @@ -1048,6 +1048,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(box mir::transform::inline::Inline); passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::copy_prop::CopyPropagation); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 9810f121ef2c1..36b67eeefd4f4 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -1127,6 +1128,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0b0a9e51cacb0..431edb3c9bc4d 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -358,39 +358,45 @@ impl EmitterWriter { let mut annotations_position = vec![]; let mut line_len = 0; let mut p = 0; - let mut ann_iter = annotations.iter().peekable(); - while let Some(annotation) = ann_iter.next() { - let peek = ann_iter.peek(); - if let Some(next) = peek { - if overlaps(next, annotation) && !annotation.is_line() && !next.is_line() + for (i, annotation) in annotations.iter().enumerate() { + for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) // This label overlaps with another one and both + && !annotation.is_line() // take space (they have text and are not + && !next.is_line() // multiline lines). && annotation.has_label() + && j > i + && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. p += 1; + break; } } annotations_position.push((p, annotation)); - if let Some(next) = peek { - let l = if let Some(ref label) = next.label { - label.len() + 2 - } else { - 0 - }; - if (overlaps(next, annotation) // Do not allow two labels to be in the same line - || next.end_col + l > annotation.start_col) // if they overlap including - // padding, to avoid situations like: - // - // fn foo(x: u32) { - // -------^------ - // | | - // fn_spanx_span - // - && !annotation.is_line() // Do not add a new line if this annotation or the - && !next.is_line() // next are vertical line placeholders. - && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. - { - p += 1; + for (j, next) in annotations.iter().enumerate() { + if j > i { + let l = if let Some(ref label) = next.label { + label.len() + 2 + } else { + 0 + }; + if overlaps(next, annotation, l) // Do not allow two labels to be in the same + // line if they overlap including padding, to + // avoid situations like: + // + // fn foo(x: u32) { + // -------^------ + // | | + // fn_spanx_span + // + && !annotation.is_line() // Do not add a new line if this annotation + && !next.is_line() // or the next are vertical line placeholders. + && annotation.has_label() // Both labels must have some text, otherwise + && next.has_label() // they are not overlapping. + { + p += 1; + break; + } } } if line_len < p { @@ -1088,8 +1094,8 @@ fn num_overlap(a_start: usize, a_end: usize, b_start: usize, b_end:usize, inclus (b_start..b_end + extra).contains(a_start) || (a_start..a_end + extra).contains(b_start) } -fn overlaps(a1: &Annotation, a2: &Annotation) -> bool { - num_overlap(a1.start_col, a1.end_col, a2.start_col, a2.end_col, false) +fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool { + num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false) } fn emit_to_destination(rendered_buffer: &Vec>, diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d7bd5ed23c2b0..4c889dad8ca50 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -90,7 +90,8 @@ impl CodeSuggestion { hi_opt: Option<&Loc>) { let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); if let Some(line) = line_opt { - if line.len() > lo { + if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) { + let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi)); buf.push_str(match hi_opt { Some(hi) => &line[lo..hi], None => &line[lo..], diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee752754504..7bf2efa4b885f 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -13,6 +13,6 @@ graphviz = { path = "../libgraphviz" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 03411e01a5798..2789250649674 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -192,7 +192,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, clean_work_products.insert(wp.clone()); } - tcx.dep_graph.with_task(n, || ()); // create the node with no inputs + tcx.dep_graph.with_task(n, (), (), create_node); + + fn create_node((): (), (): ()) { + // just create the node with no inputs + } } } diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae1..c3c5461ff7c50 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 28ce9126019eb..f9b7c68587678 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -189,11 +189,38 @@ impl LintPass for UnusedUnsafe { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe { fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { + /// Return the NodeId for an enclosing scope that is also `unsafe` + fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> { + let parent_id = cx.tcx.hir.get_parent_node(id); + if parent_id != id { + if cx.tcx.used_unsafe.borrow().contains(&parent_id) { + Some(("block".to_string(), parent_id)) + } else if let Some(hir::map::NodeItem(&hir::Item { + node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _), + .. + })) = cx.tcx.hir.find(parent_id) { + Some(("fn".to_string(), parent_id)) + } else { + is_enclosed(cx, parent_id) + } + } else { + None + } + } if let hir::ExprBlock(ref blk) = e.node { // Don't warn about generated blocks, that'll just pollute the output. if blk.rules == hir::UnsafeBlock(hir::UserProvided) && !cx.tcx.used_unsafe.borrow().contains(&blk.id) { - cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block"); + + let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span, + "unnecessary `unsafe` block"); + + db.span_label(blk.span, &"unnecessary `unsafe` block"); + if let Some((kind, id)) = is_enclosed(cx, blk.id) { + db.span_note(cx.tcx.hir.span(id), + &format!("because it's nested under this `unsafe` {}", kind)); + } + db.emit(); } } } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 6f7f03ca216b9..e8b906092730e 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 49dcffb4830a1..396a4f53b3c4d 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1055,7 +1055,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { self.inject_allocator_crate(); self.inject_panic_runtime(krate); - if log_enabled!(log::INFO) { + if log_enabled!(log::LogLevel::Info) { dump_crates(&self.cstore); } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index cf2219e0e3df5..2a67b79eaa52e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -414,12 +414,13 @@ impl CrateStore for cstore::CStore { sess.imported_macro_spans.borrow_mut() .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); - LoadedMacro::MacroRules(ast::MacroDef { + LoadedMacro::MacroDef(ast::Item { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs, - body: body.into(), + node: ast::ItemKind::MacroDef(body.into()), + vis: ast::Visibility::Inherited, }) } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index de465ea92f6b8..a6771083fc34e 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -639,6 +639,34 @@ impl<'a> Context<'a> { lib.display())); continue; } + + // Ok so at this point we've determined that `(lib, kind)` above is + // a candidate crate to load, and that `slot` is either none (this + // is the first crate of its kind) or if some the previous path has + // the exact same hash (e.g. it's the exact same crate). + // + // In principle these two candidate crates are exactly the same so + // we can choose either of them to link. As a stupidly gross hack, + // however, we favor crate in the sysroot. + // + // You can find more info in rust-lang/rust#39518 and various linked + // issues, but the general gist is that during testing libstd the + // compilers has two candidates to choose from: one in the sysroot + // and one in the deps folder. These two crates are the exact same + // crate but if the compiler chooses the one in the deps folder + // it'll cause spurious errors on Windows. + // + // As a result, we favor the sysroot crate here. Note that the + // candidates are all canonicalized, so we canonicalize the sysroot + // as well. + if let Some((ref prev, _)) = ret { + let sysroot = self.sess.sysroot(); + let sysroot = sysroot.canonicalize() + .unwrap_or(sysroot.to_path_buf()); + if prev.starts_with(&sysroot) { + continue + } + } *slot = Some((hash, metadata)); ret = Some((lib, kind)); } diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 531be0b6ae9f5..6e42e02d5109b 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 69b9570200921..42d9ab4d2bf27 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { (https://github.com/rust-lang/rust/issues/39283)"); } - if temp_lifetime.is_some() { + if !expr_ty.is_never() && temp_lifetime.is_some() { this.cfg.push(block, Statement { source_info: source_info, kind: StatementKind::StorageLive(temp.clone()) diff --git a/src/librustc_mir/callgraph.rs b/src/librustc_mir/callgraph.rs new file mode 100644 index 0000000000000..69416289d8e26 --- /dev/null +++ b/src/librustc_mir/callgraph.rs @@ -0,0 +1,252 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! MIR-based callgraph. +//! +//! This only considers direct calls + +use rustc::hir::def_id::DefId; +use rustc_data_structures::graph; + +use rustc::mir::*; +use rustc::mir::visit::*; + +use rustc::ty; + +use rustc::util::nodemap::DefIdMap; + +pub struct CallGraph { + node_map: DefIdMap, + graph: graph::Graph +} + +impl CallGraph { + // FIXME: allow for construction of a callgraph that inspects + // cross-crate MIRs if available. + pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph { + let def_ids = tcx.maps.mir.borrow().keys(); + + let mut callgraph = CallGraph { + node_map: DefIdMap(), + graph: graph::Graph::new() + }; + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let idx = callgraph.add_node(def_id); + + let mut call_visitor = CallVisitor { + caller: idx, + graph: &mut callgraph + }; + + let mir = tcx.item_mir(def_id); + call_visitor.visit_mir(&mir); + } + + callgraph + } + + // Iterate over the strongly-connected components of the graph + pub fn scc_iter(&self) -> SCCIterator { + SCCIterator::new(&self.graph) + } + + // Get the def_id for the given graph node + pub fn def_id(&self, node: graph::NodeIndex) -> DefId { + *self.graph.node_data(node) + } + + fn add_node(&mut self, id: DefId) -> graph::NodeIndex { + let graph = &mut self.graph; + *self.node_map.entry(id).or_insert_with(|| { + graph.add_node(id) + }) + } +} + +struct CallVisitor<'a> { + caller: graph::NodeIndex, + graph: &'a mut CallGraph +} + +impl<'a, 'tcx> Visitor<'tcx> for CallVisitor<'a> { + fn visit_terminator_kind(&mut self, _block: BasicBlock, + kind: &TerminatorKind<'tcx>, _loc: Location) { + if let TerminatorKind::Call { + func: Operand::Constant(ref f) + , .. } = *kind { + if let ty::TyFnDef(def_id, _, _) = f.ty.sty { + let callee = self.graph.add_node(def_id); + self.graph.graph.add_edge(self.caller, callee, ()); + } + } + } +} + +struct StackElement<'g> { + node: graph::NodeIndex, + lowlink: usize, + children: graph::AdjacentTargets<'g, DefId, ()> +} + +/** + * Iterator over strongly-connected-components using Tarjan's algorithm[1] + * + * [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm + */ +pub struct SCCIterator<'g> { + graph: &'g graph::Graph, + index: usize, + node_indices: Vec>, + scc_stack: Vec, + current_scc: Vec, + visit_stack: Vec>, +} + +impl<'g> SCCIterator<'g> { + pub fn new(graph: &'g graph::Graph) -> SCCIterator<'g> { + if graph.len_nodes() == 0 { + return SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::new(), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + } + + let first = graph::NodeIndex(0); + + SCCIterator::with_entry(graph, first) + } + + pub fn with_entry(graph: &'g graph::Graph, + entry: graph::NodeIndex) -> SCCIterator<'g> { + let mut iter = SCCIterator { + graph: graph, + index: 0, + node_indices: Vec::with_capacity(graph.len_nodes()), + scc_stack: Vec::new(), + current_scc: Vec::new(), + visit_stack: Vec::new() + }; + + iter.visit_one(entry); + + iter + } + + fn get_next(&mut self) { + self.current_scc.clear(); + + while !self.visit_stack.is_empty() { + self.visit_children(); + + let node = self.visit_stack.pop().unwrap(); + + if let Some(last) = self.visit_stack.last_mut() { + if last.lowlink > node.lowlink { + last.lowlink = node.lowlink; + } + } + + debug!("TarjanSCC: Popped node {:?} : lowlink = {:?}; index = {:?}", + node.node, node.lowlink, self.node_index(node.node).unwrap()); + + if node.lowlink != self.node_index(node.node).unwrap() { + continue; + } + + loop { + let n = self.scc_stack.pop().unwrap(); + self.current_scc.push(n); + self.set_node_index(n, !0); + if n == node.node { return; } + } + } + } + + fn visit_one(&mut self, node: graph::NodeIndex) { + self.index += 1; + let idx = self.index; + self.set_node_index(node, idx); + self.scc_stack.push(node); + self.visit_stack.push(StackElement { + node: node, + lowlink: self.index, + children: self.graph.successor_nodes(node) + }); + debug!("TarjanSCC: Node {:?} : index = {:?}", node, idx); + } + + fn visit_children(&mut self) { + while let Some(child) = self.visit_stack.last_mut().unwrap().children.next() { + if let Some(child_num) = self.node_index(child) { + let cur = self.visit_stack.last_mut().unwrap(); + if cur.lowlink > child_num { + cur.lowlink = child_num; + } + } else { + self.visit_one(child); + } + } + } + + fn node_index(&self, node: graph::NodeIndex) -> Option { + self.node_indices.get(node.node_id()).and_then(|&idx| idx) + } + + fn set_node_index(&mut self, node: graph::NodeIndex, idx: usize) { + let i = node.node_id(); + if i >= self.node_indices.len() { + self.node_indices.resize(i + 1, None); + } + self.node_indices[i] = Some(idx); + } +} + +impl<'g> Iterator for SCCIterator<'g> { + type Item = Vec; + + fn next(&mut self) -> Option> { + self.get_next(); + + if self.current_scc.is_empty() { + // Try a new root for the next SCC, if the node_indices + // map is doesn't contain all nodes, use the smallest one + // with no entry, otherwise find the first empty node. + // + // FIXME: This should probably use a set of precomputed + // roots instead + if self.node_indices.len() < self.graph.len_nodes() { + let idx = graph::NodeIndex(self.node_indices.len()); + self.visit_one(idx); + } else { + for idx in 0..self.node_indices.len() { + if self.node_indices[idx].is_none() { + let idx = graph::NodeIndex(idx); + self.visit_one(idx); + break; + } + } + } + self.get_next(); + } + + if self.current_scc.is_empty() { + None + } else { + Some(self.current_scc.clone()) + } + } +} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index a97495a0ebcc4..f21f1881c832e 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,6 +46,7 @@ extern crate rustc_const_eval; pub mod diagnostics; pub mod build; +pub mod callgraph; pub mod def_use; pub mod graphviz; mod hair; @@ -58,4 +59,4 @@ use rustc::ty::maps::Providers; pub fn provide(providers: &mut Providers) { mir_map::provide(providers); transform::qualify_consts::provide(providers); -} +} \ No newline at end of file diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index a41489ff89ff4..58f23a5c81bd7 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -38,11 +38,13 @@ use std::cell::RefCell; use std::mem; pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::MirKrate, || { + tcx.dep_graph.with_task(DepNode::MirKrate, tcx, (), build_mir_for_crate_task); + + fn build_mir_for_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { tcx.item_mir(body_owner_def_id); }); - }); + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs new file mode 100644 index 0000000000000..80a9c06f11b28 --- /dev/null +++ b/src/librustc_mir/transform/inline.rs @@ -0,0 +1,836 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Inlining pass for MIR functions + +use rustc::hir::def_id::DefId; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::graph; + +use rustc::dep_graph::DepNode; +use rustc::mir::*; +use rustc::mir::transform::{MirMapPass, MirPassHook, MirSource, Pass}; +use rustc::mir::visit::*; +use rustc::traits; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::{Subst,Substs}; +use rustc::util::nodemap::{DefIdSet}; + +use super::simplify::{remove_dead_blocks, CfgSimplifier}; + +use syntax::{attr}; +use syntax::abi::Abi; + +use callgraph; + +const DEFAULT_THRESHOLD: usize = 50; +const HINT_THRESHOLD: usize = 100; + +const INSTR_COST: usize = 5; +const CALL_PENALTY: usize = 25; + +const UNKNOWN_SIZE_COST: usize = 10; + +pub struct Inline; + +impl<'tcx> MirMapPass<'tcx> for Inline { + fn run_pass<'a>( + &mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + hooks: &mut [Box MirPassHook<'s>>]) { + + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; } + + let _ignore = tcx.dep_graph.in_ignore(); + + let callgraph = callgraph::CallGraph::build(tcx); + + let mut inliner = Inliner { + tcx: tcx, + }; + + let def_ids = tcx.maps.mir.borrow().keys(); + for &def_id in &def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = if let Some(mir) = tcx.maps.mir.borrow().get(&def_id) { + mir.borrow_mut() + } else { + continue; + }; + + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, false); + } + } + + for scc in callgraph.scc_iter() { + inliner.inline_scc(&callgraph, &scc); + } + + for def_id in def_ids { + if !def_id.is_local() { continue; } + + let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); + let mut mir = tcx.maps.mir.borrow()[&def_id].borrow_mut(); + tcx.dep_graph.write(DepNode::Mir(def_id)); + + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let src = MirSource::from_node(tcx, id); + + for hook in &mut *hooks { + hook.on_mir_pass(tcx, src, &mut mir, self, true); + } + } + } +} + +impl<'tcx> Pass for Inline { } + +struct Inliner<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +#[derive(Copy, Clone)] +struct CallSite<'tcx> { + caller: DefId, + callee: DefId, + substs: &'tcx Substs<'tcx>, + bb: BasicBlock, + location: SourceInfo, +} + +impl<'a, 'tcx> Inliner<'a, 'tcx> { + fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool { + let mut callsites = Vec::new(); + let mut in_scc = DefIdSet(); + + let mut inlined_into = DefIdSet(); + + for &node in scc { + let def_id = callgraph.def_id(node); + + // Don't inspect functions from other crates + let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { + id + } else { + continue; + }; + let src = MirSource::from_node(self.tcx, id); + if let MirSource::Fn(_) = src { + if let Some(mir) = self.tcx.maybe_item_mir(def_id) { + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + // Don't inline calls that are in cleanup blocks. + if bb_data.is_cleanup { continue; } + + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + callsites.push(CallSite { + caller: def_id, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + + in_scc.insert(def_id); + } + } + } + + // Move callsites that are in the the SCC to the end so + // they're inlined after calls to outside the SCC + let mut first_call_in_scc = callsites.len(); + + let mut i = 0; + while i < first_call_in_scc { + let f = callsites[i].caller; + if in_scc.contains(&f) { + first_call_in_scc -= 1; + callsites.swap(i, first_call_in_scc); + } else { + i += 1; + } + } + + let mut local_change; + let mut changed = false; + + loop { + local_change = false; + let mut csi = 0; + while csi < callsites.len() { + let callsite = callsites[csi]; + csi += 1; + + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + self.tcx.dep_graph.write(DepNode::Mir(callsite.caller)); + + let callee_mir = { + if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) { + if !self.should_inline(callsite, &callee_mir) { + continue; + } + + callee_mir.subst(self.tcx, callsite.substs) + } else { + continue; + } + + }; + + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&callsite.caller).unwrap(); + mir.borrow_mut() + }; + + let start = caller_mir.basic_blocks().len(); + + if !self.inline_call(callsite, &mut caller_mir, callee_mir) { + continue; + } + + inlined_into.insert(callsite.caller); + + // Add callsites from inlined function + for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated().skip(start) { + // Only consider direct calls to functions + let terminator = bb_data.terminator(); + if let TerminatorKind::Call { + func: Operand::Constant(ref f), .. } = terminator.kind { + if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty { + // Don't inline the same function multiple times. + if callsite.callee != callee_def_id { + callsites.push(CallSite { + caller: callsite.caller, + callee: callee_def_id, + substs: substs, + bb: bb, + location: terminator.source_info + }); + } + } + } + } + + csi -= 1; + if scc.len() == 1 { + callsites.swap_remove(csi); + } else { + callsites.remove(csi); + } + + local_change = true; + changed = true; + } + + if !local_change { + break; + } + } + + // Simplify functions we inlined into. + for def_id in inlined_into { + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id)); + self.tcx.dep_graph.write(DepNode::Mir(def_id)); + + let mut caller_mir = { + let map = self.tcx.maps.mir.borrow(); + let mir = map.get(&def_id).unwrap(); + mir.borrow_mut() + }; + + debug!("Running simplify cfg on {:?}", def_id); + CfgSimplifier::new(&mut caller_mir).simplify(); + remove_dead_blocks(&mut caller_mir); + } + changed + } + + fn should_inline(&self, callsite: CallSite<'tcx>, + callee_mir: &'a Mir<'tcx>) -> bool { + + let tcx = self.tcx; + + // Don't inline closures that have captures + // FIXME: Handle closures better + if callee_mir.upvar_decls.len() > 0 { + return false; + } + + + let attrs = tcx.get_attrs(callsite.callee); + let hint = attr::find_inline_attr(None, &attrs[..]); + + let hinted = match hint { + // Just treat inline(always) as a hint for now, + // there are cases that prevent inlining that we + // need to check for first. + attr::InlineAttr::Always => true, + attr::InlineAttr::Never => return false, + attr::InlineAttr::Hint => true, + attr::InlineAttr::None => false, + }; + + // Only inline local functions if they would be eligible for cross-crate + // inlining. This is to ensure that the final crate doesn't have MIR that + // reference unexported symbols + if callsite.callee.is_local() { + if callsite.substs.types().count() == 0 && !hinted { + return false; + } + } + + let mut threshold = if hinted { + HINT_THRESHOLD + } else { + DEFAULT_THRESHOLD + }; + + // Significantly lower the threshold for inlining cold functions + if attr::contains_name(&attrs[..], "cold") { + threshold /= 5; + } + + // Give a bonus functions with a small number of blocks, + // We normally have two or three blocks for even + // very small functions. + if callee_mir.basic_blocks().len() <= 3 { + threshold += threshold / 4; + } + + // FIXME: Give a bonus to functions with only a single caller + + let id = tcx.hir.as_local_node_id(callsite.caller).expect("Caller not local"); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); + + let mut first_block = true; + let mut cost = 0; + + // Traverse the MIR manually so we can account for the effects of + // inlining on the CFG. + let mut work_list = vec![START_BLOCK]; + let mut visited = BitVector::new(callee_mir.basic_blocks().len()); + while let Some(bb) = work_list.pop() { + if !visited.insert(bb.index()) { continue; } + let blk = &callee_mir.basic_blocks()[bb]; + + for stmt in &blk.statements { + // Don't count StorageLive/StorageDead in the inlining cost. + match stmt.kind { + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) | + StatementKind::Nop => {} + _ => cost += INSTR_COST + } + } + let term = blk.terminator(); + let mut is_drop = false; + match term.kind { + TerminatorKind::Drop { ref location, target, unwind } | + TerminatorKind::DropAndReplace { ref location, target, unwind, .. } => { + is_drop = true; + work_list.push(target); + // If the location doesn't actually need dropping, treat it like + // a regular goto. + let ty = location.ty(&callee_mir, tcx).subst(tcx, callsite.substs); + let ty = ty.to_ty(tcx); + if tcx.type_needs_drop_given_env(ty, ¶m_env) { + cost += CALL_PENALTY; + if let Some(unwind) = unwind { + work_list.push(unwind); + } + } else { + cost += INSTR_COST; + } + } + + TerminatorKind::Unreachable | + TerminatorKind::Call { destination: None, .. } if first_block => { + // If the function always diverges, don't inline + // unless the cost is zero + threshold = 0; + } + + TerminatorKind::Call {func: Operand::Constant(ref f), .. } => { + if let ty::TyFnDef(.., f) = f.ty.sty { + // Don't give intrinsics the extra penalty for calls + if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { + cost += INSTR_COST; + } else { + cost += CALL_PENALTY; + } + } + } + TerminatorKind::Assert { .. } => cost += CALL_PENALTY, + _ => cost += INSTR_COST + } + + if !is_drop { + for &succ in &term.successors()[..] { + work_list.push(succ); + } + } + + first_block = false; + } + + // Count up the cost of local variables and temps, if we know the size + // use that, otherwise we use a moderately-large dummy cost. + + let ptr_size = tcx.data_layout.pointer_size.bytes(); + + for v in callee_mir.vars_and_temps_iter() { + let v = &callee_mir.local_decls[v]; + let ty = v.ty.subst(tcx, callsite.substs); + // Cost of the var is the size in machine-words, if we know + // it. + if let Some(size) = type_size_of(tcx, param_env.clone(), ty) { + cost += (size / ptr_size) as usize; + } else { + cost += UNKNOWN_SIZE_COST; + } + } + + debug!("Inline cost for {:?} is {}", callsite.callee, cost); + + if let attr::InlineAttr::Always = hint { + true + } else { + cost <= threshold + } + } + + + fn inline_call(&self, callsite: CallSite<'tcx>, + caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool { + + // Don't inline a function into itself + if callsite.caller == callsite.callee { return false; } + + let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller)); + + + let terminator = caller_mir[callsite.bb].terminator.take().unwrap(); + match terminator.kind { + // FIXME: Handle inlining of diverging calls + TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { + + debug!("Inlined {:?} into {:?}", callsite.callee, callsite.caller); + + let is_box_free = Some(callsite.callee) == self.tcx.lang_items.box_free_fn(); + + let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); + let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); + let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); + + for mut scope in callee_mir.visibility_scopes.iter().cloned() { + if scope.parent_scope.is_none() { + scope.parent_scope = Some(callsite.location.scope); + scope.span = callee_mir.span; + } + + scope.span = callsite.location.span; + + let idx = caller_mir.visibility_scopes.push(scope); + scope_map.push(idx); + } + + for loc in callee_mir.vars_and_temps_iter() { + let mut local = callee_mir.local_decls[loc].clone(); + + if let Some(ref mut source_info) = local.source_info { + source_info.scope = scope_map[source_info.scope]; + + source_info.span = callsite.location.span; + } + + let idx = caller_mir.local_decls.push(local); + local_map.push(idx); + } + + for p in callee_mir.promoted.iter().cloned() { + let idx = caller_mir.promoted.push(p); + promoted_map.push(idx); + } + + // If the call is something like `a[*i] = f(i)`, where + // `i : &mut usize`, then just duplicating the `a[*i]` + // Lvalue could result in two different locations if `f` + // writes to `i`. To prevent this we need to create a temporary + // borrow of the lvalue and pass the destination as `*temp` instead. + fn dest_needs_borrow(lval: &Lvalue) -> bool { + match *lval { + Lvalue::Projection(ref p) => { + match p.elem { + ProjectionElem::Deref | + ProjectionElem::Index(_) => true, + _ => dest_needs_borrow(&p.base) + } + } + // Static variables need a borrow because the callee + // might modify the same static. + Lvalue::Static(_) => true, + _ => false + } + } + + let dest = if dest_needs_borrow(&destination.0) { + debug!("Creating temp for return destination"); + let dest = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + destination.0); + + let ty = dest.ty(caller_mir, self.tcx); + + let temp = LocalDecl::new_temp(ty); + + let tmp = caller_mir.local_decls.push(temp); + let tmp = Lvalue::Local(tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(tmp.clone(), dest) + }; + caller_mir[callsite.bb] + .statements.push(stmt); + tmp.deref() + } else { + destination.0 + }; + + let return_block = destination.1; + + let args : Vec<_> = if is_box_free { + assert!(args.len() == 1); + // box_free takes a Box, but is defined with a *mut T, inlining + // needs to generate the cast. + // FIXME: we should probably just generate correct MIR in the first place... + + let arg = if let Operand::Consume(ref lval) = args[0] { + lval.clone() + } else { + bug!("Constant arg to \"box_free\""); + }; + + let ptr_ty = args[0].ty(caller_mir, self.tcx); + vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] + } else { + // Copy the arguments if needed. + self.make_call_args(args, &callsite, caller_mir) + }; + + let bb_len = caller_mir.basic_blocks().len(); + let mut integrator = Integrator { + block_idx: bb_len, + args: &args, + local_map: local_map, + scope_map: scope_map, + promoted_map: promoted_map, + _callsite: callsite, + destination: dest, + return_block: return_block, + cleanup_block: cleanup, + in_cleanup_block: false + }; + + + for (bb, mut block) in callee_mir.basic_blocks_mut().drain_enumerated(..) { + integrator.visit_basic_block_data(bb, &mut block); + caller_mir.basic_blocks_mut().push(block); + } + + let terminator = Terminator { + source_info: callsite.location, + kind: TerminatorKind::Goto { target: BasicBlock::new(bb_len) } + }; + + caller_mir[callsite.bb].terminator = Some(terminator); + + true + } + kind => { + caller_mir[callsite.bb].terminator = Some(Terminator { + source_info: terminator.source_info, + kind: kind + }); + false + } + } + } + + fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { + let arg = Rvalue::Ref( + self.tcx.mk_region(ty::ReErased), + BorrowKind::Mut, + arg.deref()); + + let ty = arg.ty(caller_mir, self.tcx); + let ref_tmp = LocalDecl::new_temp(ty); + let ref_tmp = caller_mir.local_decls.push(ref_tmp); + let ref_tmp = Lvalue::Local(ref_tmp); + + let ref_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(ref_tmp.clone(), arg) + }; + + caller_mir[callsite.bb] + .statements.push(ref_stmt); + + let pointee_ty = match ptr_ty.sty { + ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, + _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), + _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) + }; + let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); + + let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty); + + let cast_tmp = LocalDecl::new_temp(ptr_ty); + let cast_tmp = caller_mir.local_decls.push(cast_tmp); + let cast_tmp = Lvalue::Local(cast_tmp); + + let cast_stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr) + }; + + caller_mir[callsite.bb] + .statements.push(cast_stmt); + + Operand::Consume(cast_tmp) + } + + fn make_call_args(&self, args: Vec>, + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Vec> { + let tcx = self.tcx; + // FIXME: Analysis of the usage of the arguments to avoid + // unnecessary temporaries. + args.into_iter().map(|a| { + if let Operand::Consume(Lvalue::Local(local)) = a { + if caller_mir.local_kind(local) == LocalKind::Temp { + // Reuse the operand if it's a temporary already + return a; + } + } + + debug!("Creating temp for argument"); + // Otherwise, create a temporary for the arg + let arg = Rvalue::Use(a); + + let ty = arg.ty(caller_mir, tcx); + + let arg_tmp = LocalDecl::new_temp(ty); + let arg_tmp = caller_mir.local_decls.push(arg_tmp); + let arg_tmp = Lvalue::Local(arg_tmp); + + let stmt = Statement { + source_info: callsite.location, + kind: StatementKind::Assign(arg_tmp.clone(), arg) + }; + caller_mir[callsite.bb].statements.push(stmt); + Operand::Consume(arg_tmp) + }).collect() + } +} + +fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>, + ty: Ty<'tcx>) -> Option { + tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| { + ty.layout(&infcx).ok().map(|layout| { + layout.size(&tcx.data_layout).bytes() + }) + }) +} + +/** + * Integrator. + * + * Integrates blocks from the callee function into the calling function. + * Updates block indices, references to locals and other control flow + * stuff. + */ +struct Integrator<'a, 'tcx: 'a> { + block_idx: usize, + args: &'a [Operand<'tcx>], + local_map: IndexVec, + scope_map: IndexVec, + promoted_map: IndexVec, + _callsite: CallSite<'tcx>, + destination: Lvalue<'tcx>, + return_block: BasicBlock, + cleanup_block: Option, + in_cleanup_block: bool, +} + +impl<'a, 'tcx> Integrator<'a, 'tcx> { + fn update_target(&self, tgt: BasicBlock) -> BasicBlock { + let new = BasicBlock::new(tgt.index() + self.block_idx); + debug!("Updating target `{:?}`, new: `{:?}`", tgt, new); + new + } + + fn update_local(&self, local: Local) -> Option { + let idx = local.index(); + if idx < (self.args.len() + 1) { + return None; + } + let idx = idx - (self.args.len() + 1); + let local = Local::new(idx); + self.local_map.get(local).cloned() + } + + fn arg_index(&self, arg: Local) -> Option { + let idx = arg.index(); + if idx > 0 && idx <= self.args.len() { + Some(idx - 1) + } else { + None + } + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + _ctxt: LvalueContext<'tcx>, + _location: Location) { + if let Lvalue::Local(ref mut local) = *lvalue { + if let Some(l) = self.update_local(*local) { + // Temp or Var; update the local reference + *local = l; + return; + } + } + if let Lvalue::Local(local) = *lvalue { + if local == RETURN_POINTER { + // Return pointer; update the lvalue itself + *lvalue = self.destination.clone(); + } else if local.index() < (self.args.len() + 1) { + // Argument, once again update the the lvalue itself + let idx = local.index() - 1; + if let Operand::Consume(ref lval) = self.args[idx] { + *lvalue = lval.clone(); + } else { + bug!("Arg operand `{:?}` is not an Lvalue use.", idx) + } + } + } else { + self.super_lvalue(lvalue, _ctxt, _location) + } + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { + if let Operand::Consume(Lvalue::Local(arg)) = *operand { + if let Some(idx) = self.arg_index(arg) { + let new_arg = self.args[idx].clone(); + *operand = new_arg; + return; + } + } + self.super_operand(operand, location); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { + self.in_cleanup_block = data.is_cleanup; + self.super_basic_block_data(block, data); + self.in_cleanup_block = false; + } + + fn visit_terminator_kind(&mut self, block: BasicBlock, + kind: &mut TerminatorKind<'tcx>, loc: Location) { + self.super_terminator_kind(block, kind, loc); + + match *kind { + TerminatorKind::Goto { ref mut target} => { + *target = self.update_target(*target); + } + TerminatorKind::SwitchInt { ref mut targets, .. } => { + for tgt in targets { + *tgt = self.update_target(*tgt); + } + } + TerminatorKind::Drop { ref mut target, ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *unwind { + *unwind = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this drop is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *unwind = self.cleanup_block; + } + } + TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => { + if let Some((_, ref mut tgt)) = *destination { + *tgt = self.update_target(*tgt); + } + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this call is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => { + *target = self.update_target(*target); + if let Some(tgt) = *cleanup { + *cleanup = Some(self.update_target(tgt)); + } else if !self.in_cleanup_block { + // Unless this assert is in a cleanup block, add an unwind edge to + // the orignal call's cleanup block + *cleanup = self.cleanup_block; + } + } + TerminatorKind::Return => { + *kind = TerminatorKind::Goto { target: self.return_block }; + } + TerminatorKind::Resume => { + if let Some(tgt) = self.cleanup_block { + *kind = TerminatorKind::Goto { target: tgt } + } + } + TerminatorKind::Unreachable => { } + } + } + + fn visit_visibility_scope(&mut self, scope: &mut VisibilityScope) { + *scope = self.scope_map[*scope]; + } + + fn visit_literal(&mut self, literal: &mut Literal<'tcx>, loc: Location) { + if let Literal::Promoted { ref mut index } = *literal { + if let Some(p) = self.promoted_map.get(*index).cloned() { + *index = p; + } + } else { + self.super_literal(literal, loc); + } + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index ae255f70fb788..cbd054a72499b 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -20,3 +20,4 @@ pub mod dump_mir; pub mod deaggregator; pub mod instcombine; pub mod copy_prop; +pub mod inline; diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index e93a412dc744f..a762507f35e7e 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -79,7 +79,7 @@ pub struct CfgSimplifier<'a, 'tcx: 'a> { } impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { - fn new(mir: &'a mut Mir<'tcx>) -> Self { + pub fn new(mir: &'a mut Mir<'tcx>) -> Self { let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks()); // we can't use mir.predecessors() here because that counts @@ -102,7 +102,7 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { } } - fn simplify(mut self) { + pub fn simplify(mut self) { loop { let mut changed = false; @@ -137,6 +137,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { if !changed { break } } + + self.strip_nops() } // Collapse a goto chain starting from `start` @@ -231,9 +233,19 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { terminator.kind = TerminatorKind::Goto { target: first_succ }; true } + + fn strip_nops(&mut self) { + for blk in self.basic_blocks.iter_mut() { + blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind { + false + } else { + true + }) + } + } } -fn remove_dead_blocks(mir: &mut Mir) { +pub fn remove_dead_blocks(mir: &mut Mir) { let mut seen = BitVector::new(mir.basic_blocks().len()); for (bb, _) in traversal::preorder(mir) { seen.insert(bb.index()); diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml index cc710e0ac3563..d2560c2f8203f 100644 --- a/src/librustc_passes/Cargo.toml +++ b/src/librustc_passes/Cargo.toml @@ -9,10 +9,10 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file +rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 65a60732fc807..749146fe49672 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -375,9 +375,4 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.record("Attribute", Id::None, attr); } - - fn visit_macro_def(&mut self, macro_def: &'v ast::MacroDef) { - self.record("MacroDef", Id::None, macro_def); - ast_visit::walk_macro_def(self, macro_def) - } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 3700d0295e963..cdde56f5f634b 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -13,8 +13,6 @@ use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint}; use rustc::session::Session; -use rustc::mir::transform::MirMapPass; - use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; use syntax::ext::base::MacroExpanderFn; use syntax::symbol::Symbol; @@ -53,9 +51,6 @@ pub struct Registry<'a> { #[doc(hidden)] pub late_lint_passes: Vec, - #[doc(hidden)] - pub mir_passes: Vec MirMapPass<'pcx>>>, - #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, @@ -81,7 +76,6 @@ impl<'a> Registry<'a> { lint_groups: HashMap::new(), llvm_passes: vec![], attributes: vec![], - mir_passes: Vec::new(), whitelisted_custom_derives: Vec::new(), } } @@ -157,11 +151,6 @@ impl<'a> Registry<'a> { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } - /// Register a MIR pass - pub fn register_mir_pass(&mut self, pass: Box MirMapPass<'pcx>>) { - self.mir_passes.push(pass); - } - /// Register an LLVM pass. /// /// Registration with LLVM itself is handled through static C++ objects with diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 5ce4c74e735fd..0968ea31b754f 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } rustc = { path = "../librustc" } arena = { path = "../libarena" } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index da08d1b7c78e2..03c61067d64c2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -37,7 +37,6 @@ use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; -use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token; @@ -373,7 +372,7 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } - ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), + ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(), } } @@ -493,6 +492,16 @@ impl<'a> Resolver<'a> { }) } + pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> { + let def_id = self.macro_defs[&expansion]; + if let Some(id) = self.definitions.as_local_node_id(def_id) { + self.local_macro_def_scopes[&id] + } else { + let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); + self.get_extern_crate_root(module_def_id.krate) + } + } + pub fn get_macro(&mut self, def: Def) -> Rc { let def_id = match def { Def::Macro(def_id, ..) => def_id, @@ -502,22 +511,12 @@ impl<'a> Resolver<'a> { return ext.clone(); } - let mut macro_rules = match self.session.cstore.load_macro(def_id, &self.session) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + let macro_def = match self.session.cstore.load_macro(def_id, &self.session) { + LoadedMacro::MacroDef(macro_def) => macro_def, LoadedMacro::ProcMacro(ext) => return ext, }; - let mark = Mark::fresh(); - let invocation = self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(self.get_extern_crate_root(def_id.krate)), - def_index: CRATE_DEF_INDEX, - const_expr: false, - legacy_scope: Cell::new(LegacyScope::Empty), - expansion: Cell::new(LegacyScope::Empty), - }); - self.invocations.insert(mark, invocation); - macro_rules.body = mark_tts(macro_rules.stream(), mark).into(); - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_rules)); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, ¯o_def)); self.macro_map.insert(def_id, ext.clone()); ext } @@ -707,12 +706,12 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { fn visit_item(&mut self, item: &'a Item) { let macro_use = match item.node { - ItemKind::Mac(ref mac) => { - if mac.node.path.segments.is_empty() { - self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); - } else { - self.resolver.define_macro(item, &mut self.legacy_scope); - } + ItemKind::MacroDef(..) => { + self.resolver.define_macro(item, &mut self.legacy_scope); + return + } + ItemKind::Mac(..) => { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); return } ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec217..104cc78597a4a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -407,7 +407,7 @@ enum PathSource<'a> { // Trait paths in bounds or impls. Trait, // Expression paths `path`, with optional parent context. - Expr(Option<&'a ExprKind>), + Expr(Option<&'a Expr>), // Paths in path patterns `Path`. Pat, // Paths in struct expressions and patterns `Path { .. }`. @@ -464,7 +464,7 @@ impl<'a> PathSource<'a> { ValueNS => "method or associated constant", MacroNS => bug!("associated macro"), }, - PathSource::Expr(parent) => match parent { + PathSource::Expr(parent) => match parent.map(|p| &p.node) { // "function" here means "anything callable" rather than `Def::Fn`, // this is not precise but usually more helpful than just "value". Some(&ExprKind::Call(..)) => "function", @@ -779,8 +779,8 @@ enum RibKind<'a> { // We passed through a module. ModuleRibKind(Module<'a>), - // We passed through a `macro_rules!` statement with the given expansion - MacroDefinition(Mark), + // We passed through a `macro_rules!` statement + MacroDefinition(DefId), // All bindings in this rib are type parameters that can't be used // from the default of a type parameter because they're not declared @@ -997,14 +997,18 @@ impl<'a> NameBinding<'a> { } } - fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + fn def_ignoring_ambiguity(&self) -> Def { match self.kind { - NameBindingKind::Import { binding, .. } => binding.get_macro(resolver), - NameBindingKind::Ambiguity { b1, .. } => b1.get_macro(resolver), - _ => resolver.get_macro(self.def()), + NameBindingKind::Import { binding, .. } => binding.def_ignoring_ambiguity(), + NameBindingKind::Ambiguity { b1, .. } => b1.def_ignoring_ambiguity(), + _ => self.def(), } } + fn get_macro(&self, resolver: &mut Resolver<'a>) -> Rc { + resolver.get_macro(self.def_ignoring_ambiguity()) + } + // We sometimes need to treat variants as `pub` for backwards compatibility fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() { ty::Visibility::Public } else { self.vis } @@ -1092,10 +1096,6 @@ pub struct Resolver<'a> { pub definitions: Definitions, - // Maps the node id of a statement to the expansions of the `macro_rules!`s - // immediately above the statement (if appropriate). - macros_at_scope: FxHashMap>, - graph_root: Module<'a>, prelude: Option>, @@ -1171,12 +1171,13 @@ pub struct Resolver<'a> { dummy_binding: &'a NameBinding<'a>, use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` - pub exported_macros: Vec, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet, builtin_macros: FxHashMap>, lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, + macro_defs: FxHashMap, + local_macro_def_scopes: FxHashMap>, macro_exports: Vec, pub whitelisted_legacy_custom_derives: Vec, pub found_unresolved_macro: bool, @@ -1305,11 +1306,13 @@ impl<'a> Resolver<'a> { let features = session.features.borrow(); + let mut macro_defs = FxHashMap(); + macro_defs.insert(Mark::root(), root_def_id); + Resolver { session: session, definitions: definitions, - macros_at_scope: FxHashMap(), // The outermost module has def ID 0; this is not reflected in the // AST. @@ -1365,7 +1368,6 @@ impl<'a> Resolver<'a> { // `#![feature(proc_macro)]` implies `#[feature(extern_macros)]` use_extern_macros: features.use_extern_macros || features.proc_macro, - exported_macros: Vec::new(), crate_loader: crate_loader, macro_names: FxHashSet(), builtin_macros: FxHashMap(), @@ -1373,6 +1375,8 @@ impl<'a> Resolver<'a> { macro_map: FxHashMap(), macro_exports: Vec::new(), invocations: invocations, + macro_defs: macro_defs, + local_macro_def_scopes: FxHashMap(), name_already_seen: FxHashMap(), whitelisted_legacy_custom_derives: Vec::new(), proc_macro_enabled: features.proc_macro, @@ -1510,12 +1514,12 @@ impl<'a> Resolver<'a> { } } - if let MacroDefinition(mac) = self.ribs[ns][i].kind { + if let MacroDefinition(def) = self.ribs[ns][i].kind { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } } @@ -1523,11 +1527,12 @@ impl<'a> Resolver<'a> { None } - fn resolve_crate_var(&mut self, mut crate_var_ctxt: SyntaxContext) -> Module<'a> { - while crate_var_ctxt.source().0 != SyntaxContext::empty() { - crate_var_ctxt = crate_var_ctxt.source().0; + fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> { + let mut ctxt_data = crate_var_ctxt.data(); + while ctxt_data.prev_ctxt != SyntaxContext::empty() { + ctxt_data = ctxt_data.prev_ctxt.data(); } - let module = self.invocations[&crate_var_ctxt.source().1].module.get(); + let module = self.macro_def_scope(ctxt_data.outer_mark); if module.is_local() { self.graph_root } else { module } } @@ -1579,12 +1584,12 @@ impl<'a> Resolver<'a> { NormalRibKind => { // Continue } - MacroDefinition(mac) => { + MacroDefinition(def) => { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - let (source_ctxt, source_macro) = ident.ctxt.source(); - if source_macro == mac { - ident.ctxt = source_ctxt; + let ctxt_data = ident.ctxt.data(); + if def == self.macro_defs[&ctxt_data.outer_mark] { + ident.ctxt = ctxt_data.prev_ctxt; } } _ => { @@ -1696,7 +1701,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { // do nothing, these are just around to be encoded } @@ -2031,11 +2036,12 @@ impl<'a> Resolver<'a> { // Descend into the block. for stmt in &block.stmts { - if let Some(marks) = self.macros_at_scope.remove(&stmt.id) { - num_macro_definition_ribs += marks.len() as u32; - for mark in marks { - self.ribs[ValueNS].push(Rib::new(MacroDefinition(mark))); - self.label_ribs.push(Rib::new(MacroDefinition(mark))); + if let ast::StmtKind::Item(ref item) = stmt.node { + if let ast::ItemKind::MacroDef(..) = item.node { + num_macro_definition_ribs += 1; + let def = self.definitions.local_def_id(item.id); + self.ribs[ValueNS].push(Rib::new(MacroDefinition(def))); + self.label_ribs.push(Rib::new(MacroDefinition(def))); } } @@ -2194,7 +2200,8 @@ impl<'a> Resolver<'a> { source: PathSource) -> PathResolution { let segments = &path.segments.iter().map(|seg| seg.identifier).collect::>(); - self.smart_resolve_path_fragment(id, qself, segments, path.span, source) + let ident_span = path.segments.last().map_or(path.span, |seg| seg.span); + self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source) } fn smart_resolve_path_fragment(&mut self, @@ -2202,6 +2209,7 @@ impl<'a> Resolver<'a> { qself: Option<&QSelf>, path: &[Ident], span: Span, + ident_span: Span, source: PathSource) -> PathResolution { let ns = source.namespace(); @@ -2213,9 +2221,9 @@ impl<'a> Resolver<'a> { let expected = source.descr_expected(); let path_str = names_to_string(path); let code = source.error_code(def.is_some()); - let (base_msg, fallback_label) = if let Some(def) = def { + let (base_msg, fallback_label, base_span) = if let Some(def) = def { (format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str), - format!("not a {}", expected)) + format!("not a {}", expected), span) } else { let item_str = path[path.len() - 1]; let (mod_prefix, mod_str) = if path.len() == 1 { @@ -2231,9 +2239,9 @@ impl<'a> Resolver<'a> { (mod_prefix, format!("`{}`", names_to_string(mod_path))) }; (format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str)) + format!("not found in {}", mod_str), ident_span) }; - let mut err = this.session.struct_span_err_with_code(span, &base_msg, code); + let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code); // Emit special messages for unresolved `Self` and `self`. if is_self_type(path, ns) { @@ -2291,15 +2299,15 @@ impl<'a> Resolver<'a> { err.span_label(span, &format!("type aliases cannot be used for traits")); return err; } - (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent { + (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { ExprKind::Field(_, ident) => { - err.span_label(span, &format!("did you mean `{}::{}`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}`?", + path_str, ident.node)); return err; } ExprKind::MethodCall(ident, ..) => { - err.span_label(span, &format!("did you mean `{}::{}(...)`?", - path_str, ident.node)); + err.span_label(parent.span, &format!("did you mean `{}::{}(...)`?", + path_str, ident.node)); return err; } _ => {} @@ -2324,12 +2332,12 @@ impl<'a> Resolver<'a> { // Try Levenshtein if nothing else worked. if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) { - err.span_label(span, &format!("did you mean `{}`?", candidate)); + err.span_label(ident_span, &format!("did you mean `{}`?", candidate)); return err; } // Fallback label. - err.span_label(span, &fallback_label); + err.span_label(base_span, &fallback_label); err }; let report_errors = |this: &mut Self, def: Option| { @@ -2449,7 +2457,7 @@ impl<'a> Resolver<'a> { // Make sure `A::B` in `::B::C` is a trait item. let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; let res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1], - span, PathSource::TraitItem(ns)); + span, span, PathSource::TraitItem(ns)); return Some(PathResolution::with_unresolved_segments( res.base_def(), res.unresolved_segments() + path.len() - qself.position - 1 )); @@ -2807,7 +2815,7 @@ impl<'a> Resolver<'a> { path: &[Ident], ns: Namespace, filter_fn: FilterFn) - -> Option + -> Option where FilterFn: Fn(Def) -> bool { let add_module_candidates = |module: Module, names: &mut Vec| { @@ -2821,7 +2829,7 @@ impl<'a> Resolver<'a> { }; let mut names = Vec::new(); - let prefix_str = if path.len() == 1 { + if path.len() == 1 { // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { @@ -2855,21 +2863,19 @@ impl<'a> Resolver<'a> { names.push(*name); } } - String::new() } else { // Search in module. let mod_path = &path[..path.len() - 1]; if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) { add_module_candidates(module, &mut names); } - names_to_string(mod_path) + "::" - }; + } let name = path[path.len() - 1].name; // Make sure error reporting is deterministic. names.sort_by_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { - Some(found) if found != name => Some(format!("{}{}", prefix_str, found)), + Some(found) if found != name => Some(found), _ => None, } } @@ -2892,7 +2898,7 @@ impl<'a> Resolver<'a> { self.with_resolved_label(label, id, |this| this.visit_block(block)); } - fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) { + fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -2973,11 +2979,11 @@ impl<'a> Resolver<'a> { // Equivalent to `visit::walk_expr` + passing some context to children. ExprKind::Field(ref subexpression, _) => { - self.resolve_expr(subexpression, Some(&expr.node)); + self.resolve_expr(subexpression, Some(expr)); } ExprKind::MethodCall(_, ref types, ref arguments) => { let mut arguments = arguments.iter(); - self.resolve_expr(arguments.next().unwrap(), Some(&expr.node)); + self.resolve_expr(arguments.next().unwrap(), Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } @@ -2993,7 +2999,7 @@ impl<'a> Resolver<'a> { }); } ExprKind::Call(ref callee, ref arguments) => { - self.resolve_expr(callee, Some(&expr.node)); + self.resolve_expr(callee, Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } @@ -3124,11 +3130,10 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(ident.into()); + segms.push(ast::PathSegment::from_ident(ident, name_binding.span)); let path = Path { - span: span, + span: name_binding.span, segments: segms, }; // the entity is accessible in the following cases: @@ -3148,7 +3153,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ident.into()); + path_segments.push(ast::PathSegment::from_ident(ident, name_binding.span)); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007d2..dbdf3a0b21e69 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,25 +17,26 @@ use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex} use rustc::hir::def::{Def, Export}; use rustc::hir::map::{self, DefCollector}; use rustc::ty; -use std::cell::Cell; -use std::rc::Rc; use syntax::ast::{self, Name, Ident}; -use syntax::attr; +use syntax::attr::{self, HasAttrs}; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; -use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension}; -use syntax::ext::base::MacroKind; -use syntax::ext::expand::{Expansion, mark_tts}; +use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; +use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; +use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc}; use syntax::ext::hygiene::Mark; +use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax::visit::Visitor; use syntax_pos::{Span, DUMMY_SP}; +use std::cell::Cell; +use std::mem; +use std::rc::Rc; + #[derive(Clone)] pub struct InvocationData<'a> { pub module: Cell>, @@ -73,7 +74,7 @@ pub enum LegacyScope<'a> { pub struct LegacyBinding<'a> { pub parent: Cell>, pub name: ast::Name, - ext: Rc, + def_id: DefId, pub span: Span, } @@ -110,8 +111,11 @@ impl<'a> base::Resolver for Resolver<'a> { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); if !module.is_local() { + let span = path.segments[0].span; path.segments.insert(1, match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), + ModuleKind::Def(_, name) => ast::PathSegment::from_ident( + ast::Ident::with_empty_ctxt(name), span + ), _ => unreachable!(), }) } @@ -151,7 +155,7 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.expansion.set(visitor.legacy_scope); } - fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc) { let def_id = DefId { krate: BUILTIN_MACROS_CRATE, index: DefIndex::new(self.macro_map.len()), @@ -167,10 +171,6 @@ impl<'a> base::Resolver for Resolver<'a> { self.builtin_macros.insert(ident.name, binding); } - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { - self.macros_at_scope.insert(id, macros); - } - fn resolve_imports(&mut self) { ImportResolver { resolver: self }.resolve_imports() } @@ -240,8 +240,83 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy> { + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy> { + let def = match invoc.kind { + InvocationKind::Attr { attr: None, .. } => return Ok(None), + _ => match self.resolve_invoc_to_def(invoc, scope, force) { + Ok(def) => def, + Err(determinacy) => return Err(determinacy), + }, + }; + self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + Ok(Some(self.get_macro(def))) + } + + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy> { + self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def)) + } +} + +impl<'a> Resolver<'a> { + fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result { + let (attr, traits, item) = match invoc.kind { + InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), + InvocationKind::Bang { ref mac, .. } => { + return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); + } + InvocationKind::Derive { name, span, .. } => { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force); + } + }; + + let (attr_name, path) = { + let attr = attr.as_ref().unwrap(); + (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) + }; + + let mut determined = true; + match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { + Ok(def) => return Ok(def), + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), + Err(Determinacy::Determined) => {} + } + + for &(name, span) in traits { + let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); + match self.resolve_macro(scope, &path, MacroKind::Derive, force) { + Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { + if inert_attrs.contains(&attr_name) { + // FIXME(jseyfried) Avoid `mem::replace` here. + let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + .make_items().pop().unwrap(); + let dummy_item = Annotatable::Item(dummy_item); + *item = mem::replace(item, dummy_item).map_attrs(|mut attrs| { + let inert_attr = attr.take().unwrap(); + attr::mark_known(&inert_attr); + if self.proc_macro_enabled { + *attr = find_attr_invoc(&mut attrs); + } + attrs.push(inert_attr); + attrs + }); + } + return Err(Determinacy::Undetermined); + }, + Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Determined) => {} + } + } + + Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) + } + + fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result { let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = @@ -264,10 +339,10 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let ext = match self.resolve_path(&path, Some(MacroNS), None) { + let def = match self.resolve_path(&path, Some(MacroNS), None) { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), - def @ _ => Ok(self.get_macro(def)), + def @ _ => Ok(def), }, PathResult::Module(..) => unreachable!(), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), @@ -278,15 +353,15 @@ impl<'a> base::Resolver for Resolver<'a> { }; self.current_module.macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); - return ext; + return def; } let name = path[0].name; let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { - Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), - Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)), + Some(MacroBinding::Legacy(binding)) => Ok(Def::Macro(binding.def_id, MacroKind::Bang)), + Some(MacroBinding::Modern(binding)) => Ok(binding.def_ignoring_ambiguity()), None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { - Ok(binding) => Ok(binding.get_macro(self)), + Ok(binding) => Ok(binding.def_ignoring_ambiguity()), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), Err(_) => { @@ -301,9 +376,7 @@ impl<'a> base::Resolver for Resolver<'a> { result } -} -impl<'a> Resolver<'a> { // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) pub fn resolve_lexical_macro_path_segment(&mut self, ident: Ident, @@ -499,7 +572,6 @@ impl<'a> Resolver<'a> { }; let ident = Ident::from_str(name); self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro) - .as_ref().map(|s| Symbol::intern(s)) }); if let Some(suggestion) = suggestion { @@ -544,45 +616,23 @@ impl<'a> Resolver<'a> { } pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { - let tts = match item.node { - ast::ItemKind::Mac(ref mac) => mac.node.stream(), - _ => unreachable!(), - }; - - if item.ident.name == "macro_rules" { + self.local_macro_def_scopes.insert(item.id, self.current_module); + let ident = item.ident; + if ident.name == "macro_rules" { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } - let mark = Mark::from_placeholder_id(item.id); - let invocation = self.invocations[&mark]; - invocation.module.set(self.current_module); - - let mut def = ast::MacroDef { - ident: item.ident, - attrs: item.attrs.clone(), - id: ast::DUMMY_NODE_ID, - span: item.span, - body: mark_tts(tts, mark).into(), - }; - + let def_id = self.definitions.local_def_id(item.id); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, item)); + self.macro_map.insert(def_id, ext); *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { - parent: Cell::new(*legacy_scope), - name: def.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - span: def.span, + parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, })); - self.macro_names.insert(def.ident.name); + self.macro_names.insert(ident.name); - if attr::contains_name(&def.attrs, "macro_export") { - def.id = self.next_node_id(); - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(&def) - }); - self.macro_exports.push(Export { - name: def.ident.name, - def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang), - }); - self.exported_macros.push(def); + if attr::contains_name(&item.attrs, "macro_export") { + let def = Def::Macro(def_id, MacroKind::Bang); + self.macro_exports.push(Export { name: ident.name, def: def }); } } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 3d66e5a300787..3d12df19acbe2 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -9,8 +9,8 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 0a6281bf8c54c..6caf81380e40d 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -15,7 +15,7 @@ use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId}; -use syntax::ast::{self, NodeId}; +use syntax::ast::{self, Attribute, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -136,6 +136,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for extern crates. @@ -171,6 +172,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data about a function call. @@ -256,6 +258,7 @@ pub struct MethodData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for modules. @@ -271,6 +274,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a reference to a module. @@ -295,6 +299,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -309,6 +314,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -323,6 +329,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -337,6 +344,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } /// Data for a typedef. @@ -351,6 +359,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } /// Data for a reference to a type or trait. @@ -396,6 +405,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3c275e0996dac..61956e5cd9d66 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -327,6 +327,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: scope }.lower(self.tcx)); } + // With macros 2.0, we can legitimately get a ref to a macro, but + // we don't handle it properly for now (FIXME). + Def::Macro(..) => {} Def::Local(..) | Def::Upvar(..) | Def::SelfTy(..) | @@ -336,7 +339,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | - Def::Macro(..) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", @@ -373,6 +375,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -448,6 +451,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: method_data.sig, + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -519,6 +523,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: None, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -592,6 +597,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: vis, docs: docs_for_attrs(attrs), sig: None, + attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -636,6 +642,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -701,6 +708,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -727,6 +735,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), sig: sig, + attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } } @@ -798,6 +807,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.save_ctxt.sig_base(item), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -1064,6 +1074,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } @@ -1305,6 +1316,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, parent: None, docs: docs_for_attrs(&item.attrs), sig: Some(self.save_ctxt.sig_base(item)), + attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -1527,6 +1539,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: Visibility::Inherited, docs: String::new(), sig: None, + attributes: vec![], }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index fccb56e88b3de..41658dc5b1b48 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -11,8 +11,10 @@ use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::NodeId; +use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; +use syntax::print::pprust; +use syntax::symbol::Symbol; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -64,6 +66,39 @@ impl SpanData { } } +/// Represent an arbitrary attribute on a code element +#[derive(Clone, Debug, RustcEncodable)] +pub struct Attribute { + value: String, + span: SpanData, +} + +impl Lower for Vec { + type Target = Vec; + + fn lower(self, tcx: TyCtxt) -> Vec { + let doc = Symbol::intern("doc"); + self.into_iter() + // Only retain real attributes. Doc comments are lowered separately. + .filter(|attr| attr.name() != doc) + .map(|mut attr| { + // Remove the surrounding '#[..]' or '#![..]' of the pretty printed + // attribute. First normalize all inner attribute (#![..]) to outer + // ones (#[..]), then remove the two leading and the one trailing character. + attr.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&attr); + // This str slicing works correctly, because the leading and trailing characters + // are in the ASCII range and thus exactly one byte each. + let value = value[2..value.len()-1].to_string(); + + Attribute { + value: value, + span: SpanData::from_span(attr.span, tcx.sess.codemap()), + } + }).collect() + } +} + #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { pub crate_name: String, @@ -98,6 +133,7 @@ pub struct EnumData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::EnumData { @@ -115,6 +151,7 @@ impl Lower for data::EnumData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -179,6 +216,7 @@ pub struct FunctionData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::FunctionData { @@ -197,6 +235,7 @@ impl Lower for data::FunctionData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -346,6 +385,7 @@ pub struct MethodData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::MethodData { @@ -364,6 +404,7 @@ impl Lower for data::MethodData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -381,6 +422,7 @@ pub struct ModData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::ModData { @@ -398,6 +440,7 @@ impl Lower for data::ModData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -437,6 +480,7 @@ pub struct StructData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructData { @@ -455,6 +499,7 @@ impl Lower for data::StructData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -471,6 +516,7 @@ pub struct StructVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::StructVariantData { @@ -488,6 +534,7 @@ impl Lower for data::StructVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -504,6 +551,7 @@ pub struct TraitData { pub visibility: Visibility, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TraitData { @@ -521,6 +569,7 @@ impl Lower for data::TraitData { visibility: self.visibility, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -537,6 +586,7 @@ pub struct TupleVariantData { pub parent: Option, pub docs: String, pub sig: Signature, + pub attributes: Vec, } impl Lower for data::TupleVariantData { @@ -554,6 +604,7 @@ impl Lower for data::TupleVariantData { parent: self.parent, docs: self.docs, sig: self.sig.lower(tcx), + attributes: self.attributes.lower(tcx), } } } @@ -570,6 +621,7 @@ pub struct TypeDefData { pub parent: Option, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::TypeDefData { @@ -586,6 +638,7 @@ impl Lower for data::TypeDefData { parent: self.parent, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } @@ -675,6 +728,7 @@ pub struct VariableData { pub visibility: Visibility, pub docs: String, pub sig: Option, + pub attributes: Vec, } impl Lower for data::VariableData { @@ -694,6 +748,7 @@ impl Lower for data::VariableData { visibility: self.visibility, docs: self.docs, sig: self.sig.map(|s| s.lower(tcx)), + attributes: self.attributes.lower(tcx), } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 09752994290c9..1b72489f83c67 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -87,6 +87,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, }; if def.span.file_name != def.value { // If the module is an out-of-line defintion, then we'll make the @@ -232,6 +233,7 @@ struct Def { decl_id: Option, docs: String, sig: Option, + attributes: Vec, } #[derive(Debug, RustcEncodable)] @@ -274,6 +276,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -291,6 +294,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -307,6 +311,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -323,6 +328,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -339,6 +345,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -355,6 +362,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -371,6 +379,7 @@ impl From for Def { decl_id: data.decl_id.map(|id| From::from(id)), docs: data.docs, sig: Some(From::from(data.sig)), + attributes: data.attributes, } } } @@ -387,6 +396,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: vec![], } } } @@ -403,6 +413,7 @@ impl From for Def { decl_id: None, docs: String::new(), sig: data.sig.map(|s| From::from(s)), + attributes: data.attributes, } } } @@ -424,6 +435,7 @@ impl From for Def { decl_id: None, docs: data.docs, sig: None, + attributes: data.attributes, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b1e435dcc751c..111c8370be2b1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -136,6 +136,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: item.attrs.clone(), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -164,6 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: item.attrs.clone(), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -183,6 +185,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base(item)), + attributes: item.attrs.clone(), })) } ast::ItemKind::Mod(ref m) => { @@ -205,6 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: item.attrs.clone(), })) } ast::ItemKind::Enum(ref def, _) => { @@ -228,6 +232,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: self.sig_base(item), + attributes: item.attrs.clone(), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { @@ -315,6 +320,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), sig: Some(sig), + attributes: field.attrs.clone(), }) } else { None @@ -327,7 +333,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, decl_id, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs, attributes) = match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) { Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) { Some(Node::NodeItem(item)) => { @@ -349,7 +355,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (result, trait_id, decl_id, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + item.attrs.to_vec()) } _ => { span_bug!(span, @@ -374,7 +381,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { (format!("::{}", self.tcx.item_path_str(def_id)), Some(def_id), None, From::from(&item.vis), - docs_for_attrs(&item.attrs)) + docs_for_attrs(&item.attrs), + item.attrs.to_vec()) } r => { span_bug!(span, @@ -387,7 +395,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } None => { - span_bug!(span, "Could not find container for method {}", id); + debug!("Could not find container for method {} at {:?}", id, span); + // This is not necessarily a bug, if there was a compilation error, the tables + // we need might not exist. + return None; } }, }; @@ -423,6 +434,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: parent_scope, docs: docs, sig: sig, + attributes: attributes, }) } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index b5c67ad998b69..07dcb2fc29dc6 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -11,7 +11,7 @@ test = false [dependencies] flate = { path = "../libflate" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 36f6fa7643909..3587ede9fafbe 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -41,7 +41,7 @@ use rustc::mir::tcx::LvalueTy; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; -use rustc::dep_graph::{DepNode, WorkProduct}; +use rustc::dep_graph::{AssertDepGraphSafe, DepNode, WorkProduct}; use rustc::hir::map as hir_map; use rustc::util::common::time; use session::config::{self, NoDebugInfo}; @@ -55,7 +55,7 @@ use builder::Builder; use callee::{Callee}; use common::{C_bool, C_bytes_in_context, C_i32, C_uint}; use collector::{self, TransItemCollectionMode}; -use common::{C_struct_in_context, C_u64, C_undef}; +use common::{C_struct_in_context, C_u64, C_undef, C_array}; use common::CrateContext; use common::{fulfill_obligation}; use common::{type_is_zero_size, val_ty}; @@ -1211,21 +1211,40 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Instantiate translation items without filling out definitions yet... for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_decl_task); + + fn trans_decl_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, linkage) in trans_items { trans_item.predefine(&ccx, linkage); } - }); + } } // ... and now that we have everything pre-defined, fill out those definitions. for ccx in crate_context_list.iter_need_trans() { - let cgu = ccx.codegen_unit(); - let trans_items = cgu.items_in_deterministic_order(tcx, &symbol_map); - tcx.dep_graph.with_task(cgu.work_product_dep_node(), || { + let dep_node = ccx.codegen_unit().work_product_dep_node(); + tcx.dep_graph.with_task(dep_node, + ccx, + AssertDepGraphSafe(symbol_map.clone()), + trans_def_task); + + fn trans_def_task<'a, 'tcx>(ccx: CrateContext<'a, 'tcx>, + symbol_map: AssertDepGraphSafe>>) { + // FIXME(#40304): Instead of this, the symbol-map should be an + // on-demand thing that we compute. + let AssertDepGraphSafe(symbol_map) = symbol_map; + let cgu = ccx.codegen_unit(); + let trans_items = cgu.items_in_deterministic_order(ccx.tcx(), &symbol_map); for (trans_item, _) in trans_items { trans_item.define(&ccx); } @@ -1243,11 +1262,29 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Create llvm.used variable + if !ccx.used_statics().borrow().is_empty() { + debug!("llvm.used"); + + let name = CString::new("llvm.used").unwrap(); + let section = CString::new("llvm.metadata").unwrap(); + let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow()); + + unsafe { + let g = llvm::LLVMAddGlobal(ccx.llmod(), + val_ty(array).to_ref(), + name.as_ptr()); + llvm::LLVMSetInitializer(g, array); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage); + llvm::LLVMSetSection(g, section.as_ptr()); + } + } + // Finalize debuginfo if ccx.sess().opts.debuginfo != NoDebugInfo { debuginfo::finalize(&ccx); } - }); + } } symbol_names_test::report_symbol_names(&shared_ccx); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bf1d9886ae7f0..cc3ddeef53940 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -275,6 +275,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, base::set_link_section(ccx, g, attrs); + if attr::contains_name(attrs, "used") { + ccx.used_statics().borrow_mut().push(g); + } + Ok(g) } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5f7549ece07b..4c073c739d551 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -10,7 +10,8 @@ use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; -use rustc::dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, WorkProduct}; +use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, + DepTrackingMapConfig, WorkProduct}; use middle::cstore::LinkMeta; use rustc::hir; use rustc::hir::def::ExportMap; @@ -136,6 +137,8 @@ pub struct LocalCrateContext<'tcx> { /// to constants.) statics_to_rauw: RefCell>, + used_statics: RefCell>, + lltypes: RefCell, Type>>, llsizingtypes: RefCell, Type>>, type_hashcodes: RefCell, String>>, @@ -274,6 +277,9 @@ pub struct CrateContext<'a, 'tcx: 'a> { index: usize, } +impl<'a, 'tcx> DepGraphSafe for CrateContext<'a, 'tcx> { +} + pub struct CrateContextIterator<'a, 'tcx: 'a> { shared: &'a SharedCrateContext<'a, 'tcx>, local_ccxs: &'a [LocalCrateContext<'tcx>], @@ -606,6 +612,7 @@ impl<'tcx> LocalCrateContext<'tcx> { impl_method_cache: RefCell::new(FxHashMap()), closure_bare_wrapper_cache: RefCell::new(FxHashMap()), statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), lltypes: RefCell::new(FxHashMap()), llsizingtypes: RefCell::new(FxHashMap()), type_hashcodes: RefCell::new(FxHashMap()), @@ -786,6 +793,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().statics_to_rauw } + pub fn used_statics<'a>(&'a self) -> &'a RefCell> { + &self.local().used_statics + } + pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> { &self.local().lltypes } diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 2c3b479c7dd0f..6f0f9cabef345 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -18,7 +18,6 @@ use rustc::mir::visit::{Visitor, LvalueContext}; use rustc::mir::traversal; use common; use super::MirContext; -use super::rvalue; pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector { let mir = mircx.mir; @@ -92,7 +91,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if let mir::Lvalue::Local(index) = *lvalue { self.mark_assigned(index); - if !rvalue::rvalue_creates_operand(rvalue) { + if !self.cx.rvalue_creates_operand(rvalue) { self.mark_as_lvalue(index); } } else { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 34d8c6500b926..9d40419d338b8 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -833,8 +833,21 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { self.trans_lvalue(bcx, dest) }; if fn_ret_ty.is_indirect() { - llargs.push(dest.llval); - ReturnDest::Nothing + match dest.alignment { + Alignment::AbiAligned => { + llargs.push(dest.llval); + ReturnDest::Nothing + }, + Alignment::Packed => { + // Currently, MIR code generation does not create calls + // that store directly to fields of packed structs (in + // fact, the calls it creates write only to temps), + // + // If someone changes that, please update this code path + // to create a temporary. + span_bug!(self.mir.span, "can't directly store to unaligned value"); + } + } } else { ReturnDest::Store(dest.llval) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b6d..3bcb6e78dce9f 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -11,20 +11,18 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout, Ty, TypeFoldable}; use rustc::mir::{self, Mir}; use rustc::mir::tcx::LvalueTy; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; -use rustc::ty::TypeFoldable; use session::config::FullDebugInfo; use base; use builder::Builder; -use common::{self, CrateContext, C_null, Funclet}; +use common::{self, CrateContext, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::{self, Instance}; use abi::FnType; -use type_of; use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; use syntax::symbol::keywords; @@ -176,23 +174,12 @@ enum LocalRef<'tcx> { impl<'tcx> LocalRef<'tcx> { fn new_operand<'a>(ccx: &CrateContext<'a, 'tcx>, - ty: ty::Ty<'tcx>) -> LocalRef<'tcx> { + ty: Ty<'tcx>) -> LocalRef<'tcx> { if common::type_is_zero_size(ccx, ty) { // Zero-size temporaries aren't always initialized, which // doesn't matter because they don't contain data, but // we need something in the operand. - let llty = type_of::type_of(ccx, ty); - let val = if common::type_is_imm_pair(ccx, ty) { - let fields = llty.field_types(); - OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) - } else { - OperandValue::Immediate(C_null(llty)) - }; - let op = OperandRef { - val: val, - ty: ty - }; - LocalRef::Operand(Some(op)) + LocalRef::Operand(Some(OperandRef::new_zst(ccx, ty))) } else { LocalRef::Operand(None) } @@ -212,15 +199,17 @@ pub fn trans_mir<'a, 'tcx: 'a>( debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir); - let bcx = Builder::new_block(ccx, llfn, "entry-block"); + let bcx = Builder::new_block(ccx, llfn, "start"); let cleanup_kinds = analyze::cleanup_kinds(&mir); - // Allocate a `Block` for every basic block + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); let block_bcxs: IndexVec = mir.basic_blocks().indices().map(|bb| { - if bb == mir::START_BLOCK { - bcx.build_sibling_block("start").llbb() + if bb == mir::START_BLOCK && !reentrant_start_block { + bcx.llbb() } else { bcx.build_sibling_block(&format!("{:?}", bb)).llbb() } @@ -307,9 +296,10 @@ pub fn trans_mir<'a, 'tcx: 'a>( .collect() }; - // Branch to the START block - let start_bcx = mircx.blocks[mir::START_BLOCK]; - bcx.br(start_bcx); + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bcx.br(mircx.blocks[mir::START_BLOCK]); + } // Up until here, IR instructions for this function have explicitly not been annotated with // source code location, so we don't step into call setup code. From here on, source location diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index cb77fcbbff85d..44fe684490fc9 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -15,7 +15,7 @@ use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use base; -use common; +use common::{self, CrateContext, C_null}; use builder::Builder; use value::Value; use type_of; @@ -77,6 +77,22 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> { } impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(ccx: &CrateContext<'a, 'tcx>, + ty: Ty<'tcx>) -> OperandRef<'tcx> { + assert!(common::type_is_zero_size(ccx, ty)); + let llty = type_of::type_of(ccx, ty); + let val = if common::type_is_imm_pair(ccx, ty) { + let fields = llty.field_types(); + OperandValue::Pair(C_null(fields[0]), C_null(fields[1])) + } else { + OperandValue::Immediate(C_null(llty)) + }; + OperandRef { + val: val, + ty: ty + } + } + /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> ValueRef { @@ -268,10 +284,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { bcx.store(base::from_immediate(bcx, s), lldest, align); } OperandValue::Pair(a, b) => { + let f_align = match *bcx.ccx.layout_of(operand.ty) { + Layout::Univariant { ref variant, .. } if variant.packed => { + Some(1) + } + _ => align + }; + let a = base::from_immediate(bcx, a); let b = base::from_immediate(bcx, b); - bcx.store(a, bcx.struct_gep(lldest, 0), align); - bcx.store(b, bcx.struct_gep(lldest, 1), align); + bcx.store(a, bcx.struct_gep(lldest, 0), f_align); + bcx.store(b, bcx.struct_gep(lldest, 1), f_align); } } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b6af4e52e820b..4328f2516970e 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } _ => { - assert!(rvalue_creates_operand(rvalue)); + assert!(self.rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); self.store_operand(&bcx, dest.llval, dest.alignment.to_align(), temp); bcx @@ -170,7 +170,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -478,8 +478,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { } mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - bug!("cannot generate operand from rvalue {:?}", rvalue); - + // According to `rvalue_creates_operand`, only ZST + // aggregate rvalues are allowed to be operands. + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + (bcx, OperandRef::new_zst(self.ccx, self.monomorphize(&ty))) } } } @@ -662,26 +664,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { OperandValue::Pair(val, of) } -} -pub fn rvalue_creates_operand(rvalue: &mir::Rvalue) -> bool { - match *rvalue { - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::CheckedBinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | - mir::Rvalue::Box(..) | - mir::Rvalue::Use(..) => - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => - false, - } + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::CheckedBinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Discriminant(..) | + mir::Rvalue::Box(..) | + mir::Rvalue::Use(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) => { + let ty = rvalue.ty(self.mir, self.ccx.tcx()); + let ty = self.monomorphize(&ty); + common::type_is_zero_size(self.ccx, ty) + } + } - // (*) this is only true if the type is suitable + // (*) this is only true if the type is suitable + } } #[derive(Copy, Clone)] diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index f08d26373e50e..07998aa4a30ea 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index ca0ab8f1e8c77..1aab4853a4f64 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -12,6 +12,7 @@ use astconv::AstConv; use super::FnCtxt; +use rustc::infer::InferOk; use rustc::traits; use rustc::ty::{self, Ty, TraitRef}; use rustc::ty::{ToPredicate, TypeFoldable}; @@ -149,6 +150,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I) where I: IntoIterator + { + let fcx = self.fcx; + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + } + + pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I) + -> InferOk<'tcx, ()> + where I: IntoIterator { let methods: Vec<_> = self.steps .iter() @@ -176,8 +185,9 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { } } - for obligation in self.obligations { - self.fcx.register_predicate(obligation); + InferOk { + value: (), + obligations: self.obligations } } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 53759cc115d1c..c43291557f7fa 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -64,7 +64,8 @@ use check::FnCtxt; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::infer::{Coercion, InferOk, TypeTrace}; +use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use rustc::ty::{self, LvaluePreference, TypeAndMut, @@ -75,9 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use syntax::abi; use syntax::feature_gate; -use util::common::indent; -use std::cell::RefCell; use std::collections::VecDeque; use std::ops::Deref; @@ -85,7 +84,6 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, - unsizing_obligations: RefCell>>, } impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { @@ -95,7 +93,7 @@ impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { } } -type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, Adjust<'tcx>)>; +type CoerceResult<'tcx> = InferResult<'tcx, Adjustment<'tcx>>; fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, to_mutbl: hir::Mutability) @@ -108,44 +106,53 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, } } +fn identity<'tcx>() -> Adjust<'tcx> { + Adjust::DerefRef { + autoderefs: 0, + autoref: None, + unsize: false, + } +} + +fn success<'tcx>(kind: Adjust<'tcx>, + target: Ty<'tcx>, + obligations: traits::PredicateObligations<'tcx>) + -> CoerceResult<'tcx> { + Ok(InferOk { + value: Adjustment { + kind, + target + }, + obligations + }) +} + impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self { Coerce { fcx: fcx, cause: cause, use_lub: false, - unsizing_obligations: RefCell::new(vec![]), } } - fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { self.commit_if_ok(|_| { let trace = TypeTrace::types(&self.cause, false, a, b); if self.use_lub { self.lub(false, trace, &a, &b) - .map(|ok| self.register_infer_ok_obligations(ok)) } else { self.sub(false, trace, &a, &b) - .map(|InferOk { value, obligations }| { - self.fcx.register_predicates(obligations); - value - }) } }) } - /// Unify two types (using sub or lub) and produce a noop coercion. - fn unify_and_identity(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - self.unify(&a, &b).and_then(|ty| self.identity(ty)) - } - - /// Synthesize an identity adjustment. - fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { - Ok((ty, Adjust::DerefRef { - autoderefs: 0, - autoref: None, - unsize: false, - })) + /// Unify two types (using sub or lub) and produce a specific coercion. + fn unify_and(&self, a: Ty<'tcx>, b: Ty<'tcx>, kind: Adjust<'tcx>) + -> CoerceResult<'tcx> { + self.unify(&a, &b).and_then(|InferOk { value: ty, obligations }| { + success(kind, ty, obligations) + }) } fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> @@ -158,11 +165,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Just ignore error types. if a.references_error() || b.references_error() { - return self.identity(b); + return success(identity(), b, vec![]); } if a.is_never() { - return Ok((b, Adjust::NeverToAny)); + return success(Adjust::NeverToAny, b, vec![]); } // Consider coercing the subtype to a DST @@ -208,7 +215,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => { // Otherwise, just use unification rules. - self.unify_and_identity(a, b) + self.unify_and(a, b, identity()) } } } @@ -240,7 +247,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; (r_a, mt_a) } - _ => return self.unify_and_identity(a, b), + _ => return self.unify_and(a, b, identity()), }; let span = self.cause.span; @@ -248,7 +255,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut first_error = None; let mut r_borrow_var = None; let mut autoderef = self.autoderef(span, a); - let mut success = None; + let mut found = None; for (referent_ty, autoderefs) in autoderef.by_ref() { if autoderefs == 0 { @@ -346,8 +353,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mt_b.mutbl, // [1] above }); match self.unify(derefd_ty_a, b) { - Ok(ty) => { - success = Some((ty, autoderefs)); + Ok(ok) => { + found = Some((ok, autoderefs)); break; } Err(err) => { @@ -363,7 +370,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // (e.g., in example above, the failure from relating `Vec` // to the target type), since that should be the least // confusing. - let (ty, autoderefs) = match success { + let (InferOk { value: ty, mut obligations }, autoderefs) = match found { Some(d) => d, None => { let err = first_error.expect("coerce_borrowed_pointer had no error"); @@ -372,12 +379,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } }; - // This commits the obligations to the fulfillcx. After this succeeds, - // this snapshot can't be rolled back. - autoderef.finalize(LvaluePreference::from_mutbl(mt_b.mutbl), exprs()); - - // Now apply the autoref. We have to extract the region out of - // the final ref type we got. if ty == a && mt_a.mutbl == hir::MutImmutable && autoderefs == 1 { // As a special case, if we would produce `&'a *x`, that's // a total no-op. We end up with the type `&'a T` just as @@ -391,8 +392,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. assert_eq!(mt_b.mutbl, hir::MutImmutable); // can only coerce &T -> &U - return self.identity(ty); + return success(identity(), ty, obligations); } + + // Now apply the autoref. We have to extract the region out of + // the final ref type we got. let r_borrow = match ty.sty { ty::TyRef(r_borrow, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), @@ -402,11 +406,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty, autoderefs, autoref); - Ok((ty, Adjust::DerefRef { + + let pref = LvaluePreference::from_mutbl(mt_b.mutbl); + obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations); + + success(Adjust::DerefRef { autoderefs: autoderefs, autoref: autoref, unsize: false, - })) + }, ty, obligations) } @@ -445,18 +453,32 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } _ => (source, None), }; - let source = source.adjust_for_autoref(self.tcx, reborrow); + let coerce_source = source.adjust_for_autoref(self.tcx, reborrow); + + let adjust = Adjust::DerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: true, + }; + + // Setup either a subtyping or a LUB relationship between + // the `CoerceUnsized` target type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let coerce_target = self.next_ty_var(origin); + let mut coercion = self.unify_and(coerce_target, target, adjust)?; let mut selcx = traits::SelectionContext::new(self); // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); - let mut leftover_predicates = vec![]; // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.cause.span, self.body_id); queue.push_back(self.tcx - .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target])); + .predicate_for_trait_def(cause, coerce_unsized_did, 0, + coerce_source, &[coerce_target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -467,7 +489,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), _ => { - leftover_predicates.push(obligation); + coercion.obligations.push(obligation); continue; } }; @@ -495,33 +517,26 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } - *self.unsizing_obligations.borrow_mut() = leftover_predicates; - - let adjustment = Adjust::DerefRef { - autoderefs: if reborrow.is_some() { 1 } else { 0 }, - autoref: reborrow, - unsize: true, - }; - debug!("Success, coerced with {:?}", adjustment); - Ok((target, adjustment)) + Ok(coercion) } fn coerce_from_safe_fn(&self, a: Ty<'tcx>, fn_ty_a: ty::PolyFnSig<'tcx>, - b: Ty<'tcx>) + b: Ty<'tcx>, + to_unsafe: Adjust<'tcx>, + normal: Adjust<'tcx>) -> CoerceResult<'tcx> { if let ty::TyFnPtr(fn_ty_b) = b.sty { match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, Adjust::UnsafeFnPointer)); + return self.unify_and(unsafe_a, b, to_unsafe); } _ => {} } } - self.unify_and_identity(a, b) + self.unify_and(a, b, normal) } fn coerce_from_fn_pointer(&self, @@ -536,7 +551,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - self.coerce_from_safe_fn(a, fn_ty_a, b) + self.coerce_from_safe_fn(a, fn_ty_a, b, + Adjust::UnsafeFnPointer, identity()) } fn coerce_from_fn_item(&self, @@ -554,10 +570,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) - .map(|(ty, _)| (ty, Adjust::ReifyFnPointer)) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b, + Adjust::ReifyFnPointer, Adjust::ReifyFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -582,7 +598,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { self.cause.span, feature_gate::GateIssue::Language, feature_gate::CLOSURE_TO_FN_COERCION); - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -607,10 +623,9 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let pointer_ty = self.tcx.mk_fn_ptr(converted_sig); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); - self.unify_and_identity(pointer_ty, b) - .map(|(ty, _)| (ty, Adjust::ClosureFnPointer)) + self.unify_and(pointer_ty, b, Adjust::ClosureFnPointer) } - _ => self.unify_and_identity(a, b), + _ => self.unify_and(a, b, identity()), } } @@ -625,7 +640,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.unify_and_identity(a, b); + return self.unify_and(a, b, identity()); } }; @@ -634,50 +649,22 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { mutbl: mutbl_b, ty: mt_a.ty, }); - let (ty, noop) = self.unify_and_identity(a_unsafe, b)?; coerce_mutbls(mt_a.mutbl, mutbl_b)?; - // Although references and unsafe ptrs have the same // representation, we still register an Adjust::DerefRef so that // regionck knows that the region for `a` must be valid here. - Ok((ty, - if is_ref { - Adjust::DerefRef { - autoderefs: 1, - autoref: Some(AutoBorrow::RawPtr(mutbl_b)), - unsize: false, - } - } else if mt_a.mutbl != mutbl_b { - Adjust::MutToConstPointer - } else { - noop - })) - } -} - -fn apply<'a, 'b, 'gcx, 'tcx, E, I>(coerce: &mut Coerce<'a, 'gcx, 'tcx>, - exprs: &E, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> RelateResult<'tcx, Adjustment<'tcx>> - where E: Fn() -> I, - I: IntoIterator -{ - - let (ty, adjust) = indent(|| coerce.coerce(exprs, a, b))?; - - let fcx = coerce.fcx; - if let Adjust::DerefRef { unsize: true, .. } = adjust { - let mut obligations = coerce.unsizing_obligations.borrow_mut(); - for obligation in obligations.drain(..) { - fcx.register_predicate(obligation); - } + self.unify_and(a_unsafe, b, if is_ref { + Adjust::DerefRef { + autoderefs: 1, + autoref: Some(AutoBorrow::RawPtr(mutbl_b)), + unsize: false, + } + } else if mt_a.mutbl != mutbl_b { + Adjust::MutToConstPointer + } else { + identity() + }) } - - Ok(Adjustment { - kind: adjust, - target: ty - }) } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { @@ -694,9 +681,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); - let mut coerce = Coerce::new(self, cause); + let coerce = Coerce::new(self, cause); self.commit_if_ok(|_| { - let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?; + let ok = coerce.coerce(&|| Some(expr), source, target)?; + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { debug!("Success, coerced with {:?}", adjustment); match self.tables.borrow().adjustments.get(&expr.id) { @@ -773,9 +761,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // but only if the new expression has no coercion already applied to it. let mut first_error = None; if !self.tables.borrow().adjustments.contains_key(&new.id) { - let result = self.commit_if_ok(|_| apply(&mut coerce, &|| Some(new), new_ty, prev_ty)); + let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty)); match result { - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { self.write_adjustment(new.id, adjustment); } @@ -816,7 +805,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + match self.commit_if_ok(|_| coerce.coerce(&exprs, prev_ty, new_ty)) { Err(_) => { // Avoid giving strange errors on failed attempts. if let Some(e) = first_error { @@ -828,7 +817,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) } } - Ok(adjustment) => { + Ok(ok) => { + let adjustment = self.register_infer_ok_obligations(ok); if !adjustment.is_identity() { let mut tables = self.tables.borrow_mut(); for expr in exprs() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2b9ccf6d3e246..5a582a523ea1c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -539,13 +539,15 @@ pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult } pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult { - tcx.sess.track_errors(|| { - tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, || { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { - tcx.item_tables(body_owner_def_id); - }); + return tcx.sess.track_errors(|| { + tcx.dep_graph.with_task(DepNode::TypeckBodiesKrate, tcx, (), check_item_bodies_task); + }); + + fn check_item_bodies_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { + tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| { + tcx.item_tables(body_owner_def_id); }); - }) + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index db7cf3c000ba4..2417745571910 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -165,15 +165,10 @@ impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> { /// 4. This is added by the code in `visit_expr` when we write to `item_types`. /// 5. This is added by the code in `convert_item` when we write to `item_types`; /// note that this write occurs inside the `CollectItemSig` task. - /// 6. Added by explicit `read` below - fn with_collect_item_sig(&self, id: ast::NodeId, op: OP) - where OP: FnOnce() - { + /// 6. Added by reads from within `op`. + fn with_collect_item_sig(&self, id: ast::NodeId, op: fn(TyCtxt<'a, 'tcx, 'tcx>, ast::NodeId)) { let def_id = self.tcx.hir.local_def_id(id); - self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || { - self.tcx.hir.read(id); - op(); - }); + self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), self.tcx, id, op); } } @@ -183,7 +178,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item) { - self.with_collect_item_sig(item.id, || convert_item(self.tcx, item)); + self.with_collect_item_sig(item.id, convert_item); intravisit::walk_item(self, item); } @@ -216,16 +211,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_collect_item_sig(trait_item.id, || { - convert_trait_item(self.tcx, trait_item) - }); + self.with_collect_item_sig(trait_item.id, convert_trait_item); intravisit::walk_trait_item(self, trait_item); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_collect_item_sig(impl_item.id, || { - convert_impl_item(self.tcx, impl_item) - }); + self.with_collect_item_sig(impl_item.id, convert_impl_item); intravisit::walk_impl_item(self, impl_item); } } @@ -493,9 +484,10 @@ fn ensure_no_ty_param_bounds(tcx: TyCtxt, } } -fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { +fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { + let it = tcx.hir.expect_item(item_id); debug!("convert: item {} with id {}", it.name, it.id); - let def_id = tcx.hir.local_def_id(it.id); + let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { @@ -560,7 +552,8 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) { } } -fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) { +fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item_id: ast::NodeId) { + let trait_item = tcx.hir.expect_trait_item(trait_item_id); let def_id = tcx.hir.local_def_id(trait_item.id); tcx.item_generics(def_id); @@ -577,8 +570,8 @@ fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::T tcx.item_predicates(def_id); } -fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) { - let def_id = tcx.hir.local_def_id(impl_item.id); +fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item_id: ast::NodeId) { + let def_id = tcx.hir.local_def_id(impl_item_id); tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 93c0bd6d6d836..1c479ce1d0157 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -11,11 +11,13 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } +env_logger = { version = "0.4", default-features = false } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } -rustc_driver = { path = "../librustc_driver" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_driver = { path = "../librustc_driver" } rustc_errors = { path = "../librustc_errors" } rustc_lint = { path = "../librustc_lint" } rustc_metadata = { path = "../librustc_metadata" } @@ -24,7 +26,6 @@ rustc_trans = { path = "../librustc_trans" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -log = { path = "../liblog" } [build-dependencies] build_helper = { path = "../build_helper" } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 6bd9cf6620b0e..4047f6045bcc5 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -377,13 +377,13 @@ h4 > code, h3 > code, .invisible > code { .content .method .where, .content .fn .where, .content .where.fmt-newline { - display: block; + display: block; } /* Bit of whitespace to indent it */ .content .method .where::before, .content .fn .where::before, .content .where.fmt-newline::before { - content: ' '; + content: ' '; } .content .methods > div { margin-left: 40px; } @@ -506,17 +506,15 @@ body.blur > :not(#help) { } #help > div { flex: 0 0 auto; - background: #e9e9e9; box-shadow: 0 0 6px rgba(0,0,0,.2); width: 550px; height: 330px; - border: 1px solid #bfbfbf; + border: 1px solid; } #help dt { float: left; border-radius: 4px; - border: 1px solid #bfbfbf; - background: #fff; + border: 1px solid; width: 23px; text-align: center; clear: left; @@ -567,7 +565,6 @@ body.blur > :not(#help) { .since { font-weight: normal; font-size: initial; - color: grey; position: absolute; right: 0; top: 0; @@ -589,24 +586,12 @@ td.summary-column { padding-right: 0px; } -.line-numbers :target { background-color: transparent; } - -/* Code highlighting */ -pre.rust .kw { color: #8959A8; } -pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } -pre.rust .number, pre.rust .string { color: #718C00; } -pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, -pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } -pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } -pre.rust .lifetime { color: #B76514; } pre.rust .question-mark { - color: #ff9011; font-weight: bold; } pre.rust { position: relative; } a.test-arrow { - background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; padding: 5px 10px 5px 10px; @@ -616,7 +601,6 @@ a.test-arrow { right: 5px; } a.test-arrow:hover{ - background-color: #4e8bca; text-decoration: none; } @@ -660,10 +644,6 @@ a.test-arrow:hover{ text-align: center; } -.toggle-label { - color: #999; -} - .ghost { display: none; } @@ -719,8 +699,7 @@ span.since { } :target > code { - background: #FDFFD3; - opacity: 1; + opacity: 1; } /* Media Queries */ @@ -793,4 +772,4 @@ span.since { nav.sub, .content .out-of-band, .collapse-toggle { display: none; } -} +} \ No newline at end of file diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index f1e81900d1eec..40561597e93e0 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -13,28 +13,36 @@ /* General structure and fonts */ body { - background-color: white; - color: black; + background-color: white; + color: black; } h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - color: black; + color: black; } h1.fqn { - border-bottom-color: #D5D5D5; + border-bottom-color: #D5D5D5; } h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), h4:not(.method):not(.type):not(.tymethod) { - border-bottom-color: #DDDDDD; + border-bottom-color: #DDDDDD; } .in-band { - background-color: white; + background-color: white; } .docblock code, .docblock-short code { - background-color: #F5F5F5; + background-color: #F5F5F5; } pre { - background-color: #F5F5F5; + background-color: #F5F5F5; +} + +.sidebar { + background-color: #F1F1F1; +} + +.sidebar .current { + background-color: #fff; } .sidebar { @@ -46,24 +54,24 @@ pre { } .sidebar .location { - border-color: #000; - background-color: #fff; - color: #333; + border-color: #000; + background-color: #fff; + color: #333; } .block a:hover { - background: #F5F5F5; + background: #F5F5F5; } .line-numbers span { color: #c67e2d; } .line-numbers .line-highlighted { - background-color: #f6fdb0 !important; + background-color: #f6fdb0 !important; } :target { background: #FDFFD3; } .content .highlighted { - color: #000 !important; - background-color: #ccc; + color: #000 !important; + background-color: #ccc; } .content .highlighted a, .content .highlighted span { color: #000 !important; } .content .highlighted.trait { background-color: #fece7e; } @@ -76,21 +84,21 @@ pre { .content .highlighted.type { background-color: #c6afb3; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { - border-bottom-color: #DDD; + border-bottom-color: #DDD; } .docblock table { - border-color: #ddd; + border-color: #ddd; } .docblock table td { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .docblock table th { - border-top-color: #ddd; - border-bottom-color: #ddd; + border-top-color: #ddd; + border-bottom-color: #ddd; } .content span.primitive, .content a.primitive, .block a.current.primitive { color: #39a7bf; } @@ -105,34 +113,78 @@ pre.rust .comment { color: #8E908C; } pre.rust .doccomment { color: #4D4D4C; } nav { - border-bottom-color: #e0e0e0; + border-bottom-color: #e0e0e0; } nav.main .current { - border-top-color: #000; - border-bottom-color: #000; + border-top-color: #000; + border-bottom-color: #000; } nav.main .separator { - border: 1px solid #000; + border: 1px solid #000; } a { - color: #000; + color: #000; } .docblock a, .docblock-short a, .stability a { - color: #3873AD; + color: #3873AD; } a.test-arrow { - color: #f5f5f5; + color: #f5f5f5; } .content span.trait, .content a.trait, .block a.current.trait { color: #7c5af3; } .search-input { - color: #555; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; - background-color: white; + color: #555; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; + background-color: white; } .stab.unstable { background: #FFF5D6; border-color: #FFC600; } .stab.deprecated { background: #F3DFFF; border-color: #7F0087; } + +#help > div { + background: #e9e9e9; + border-color: #bfbfbf;; +} + +#help dt { + border-color: #bfbfbf; + background: #fff; +} + +.since { + color: grey; +} + +.line-numbers :target { background-color: transparent; } + +/* Code highlighting */ +pre.rust .kw { color: #8959A8; } +pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } +pre.rust .number, pre.rust .string { color: #718C00; } +pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val, +pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; } +pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; } +pre.rust .lifetime { color: #B76514; } +pre.rust .question-mark { + color: #ff9011; +} + +a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); +} + +a.test-arrow:hover{ + background-color: #4e8bca; +} + +.toggle-label { + color: #999; +} + +:target > code { + background: #FDFFD3; +} \ No newline at end of file diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 84f69cd35045c..8dd03f6edc4d5 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -30,6 +30,7 @@ extern crate arena; extern crate getopts; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_const_eval; @@ -99,6 +100,7 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32_000_000; // 32MB + env_logger::init().unwrap(); let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 42928427233d7..b80de3cc50546 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -16,6 +16,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; +use syntax::tokenstream::TokenStream; use syntax_pos::Span; use rustc::hir::map as hir_map; @@ -205,14 +206,17 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { - LoadedMacro::MacroRules(macro_rules) => macro_rules, + LoadedMacro::MacroDef(macro_def) => macro_def, // FIXME(jseyfried): document proc macro reexports LoadedMacro::ProcMacro(..) => continue, }; - // FIXME(jseyfried) merge with `self.visit_macro()` - let tts = def.stream().trees().collect::>(); - let matchers = tts.chunks(4).map(|arm| arm[0].span()).collect(); + let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node { + let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect(); + tts.chunks(4).map(|arm| arm[0].span()).collect() + } else { + unreachable!() + }; om.macros.push(Macro { def_id: def_id, attrs: def.attrs.clone().into(), diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index bc678fcb8385b..bfb0aa6e1a122 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -154,7 +154,28 @@ pub struct NulError(usize, Vec); /// byte was found too early in the slice provided or one wasn't found at all. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstr_from_bytes", since = "1.10.0")] -pub struct FromBytesWithNulError { _a: () } +pub struct FromBytesWithNulError { + kind: FromBytesWithNulErrorKind, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum FromBytesWithNulErrorKind { + InteriorNul(usize), + NotNulTerminated, +} + +impl FromBytesWithNulError { + fn interior_nul(pos: usize) -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::InteriorNul(pos), + } + } + fn not_nul_terminated() -> FromBytesWithNulError { + FromBytesWithNulError { + kind: FromBytesWithNulErrorKind::NotNulTerminated, + } + } +} /// An error returned from `CString::into_string` to indicate that a UTF-8 error /// was encountered during the conversion. @@ -458,14 +479,23 @@ impl From for io::Error { #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for FromBytesWithNulError { fn description(&self) -> &str { - "data provided is not null terminated or contains an interior nul byte" + match self.kind { + FromBytesWithNulErrorKind::InteriorNul(..) => + "data provided contains an interior nul byte", + FromBytesWithNulErrorKind::NotNulTerminated => + "data provided is not nul terminated", + } } } #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl fmt::Display for FromBytesWithNulError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) + f.write_str(self.description())?; + if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { + write!(f, " at byte pos {}", pos)?; + } + Ok(()) } } @@ -559,10 +589,14 @@ impl CStr { #[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { - if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) { - Err(FromBytesWithNulError { _a: () }) + let nul_pos = memchr::memchr(0, bytes); + if let Some(nul_pos) = nul_pos { + if nul_pos + 1 != bytes.len() { + return Err(FromBytesWithNulError::interior_nul(nul_pos)); + } + Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) } else { - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Err(FromBytesWithNulError::not_nul_terminated()) } } diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b63f..97d37266130af 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d19..a456fa512254c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -134,7 +134,7 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - segments: vec![identifier.into()], + segments: vec![PathSegment::from_ident(identifier, s)], } } @@ -159,6 +159,8 @@ impl Path { pub struct PathSegment { /// The identifier portion of this path segment. pub identifier: Ident, + /// Span of the segment identifier. + pub span: Span, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -170,16 +172,14 @@ pub struct PathSegment { pub parameters: Option>, } -impl From for PathSegment { - fn from(id: Ident) -> Self { - PathSegment { identifier: id, parameters: None } - } -} - impl PathSegment { + pub fn from_ident(ident: Ident, span: Span) -> Self { + PathSegment { identifier: ident, span: span, parameters: None } + } pub fn crate_root() -> Self { PathSegment { identifier: keywords::CrateRoot.ident(), + span: DUMMY_SP, parameters: None, } } @@ -414,7 +414,6 @@ pub struct Crate { pub module: Mod, pub attrs: Vec, pub span: Span, - pub exported_macros: Vec, } /// A spanned compile-time attribute list item. @@ -936,6 +935,8 @@ pub enum ExprKind { Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), + /// A catch block (`catch { ... }`) + Catch(P), /// An assignment (`a = foo()`) Assign(P, P), @@ -1855,10 +1856,13 @@ pub enum ItemKind { Option, // (optional) trait this impl implements P, // self Vec), - /// A macro invocation (which includes macro definition). + /// A macro invocation. /// /// E.g. `macro_rules! foo { .. }` or `foo!(..)` Mac(Mac), + + /// A macro definition. + MacroDef(ThinTokenStream), } impl ItemKind { @@ -1877,6 +1881,7 @@ impl ItemKind { ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::Mac(..) | + ItemKind::MacroDef(..) | ItemKind::Impl(..) | ItemKind::DefaultImpl(..) => "item" } @@ -1912,24 +1917,6 @@ impl ForeignItemKind { } } -/// A macro definition, in this crate or imported from another. -/// -/// Not parsed directly, but created on macro import or `macro_rules!` expansion. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct MacroDef { - pub ident: Ident, - pub attrs: Vec, - pub id: NodeId, - pub span: Span, - pub body: ThinTokenStream, -} - -impl MacroDef { - pub fn stream(&self) -> TokenStream { - self.body.clone().into() - } -} - #[cfg(test)] mod tests { use serialize; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e242cf2777fe5..dc7e7673eb03c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::{DiagnosticBuilder, FatalError}; -use ext::expand::{self, Expansion}; +use ext::expand::{self, Expansion, Invocation}; use ext::hygiene::Mark; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; @@ -552,14 +552,15 @@ pub trait Resolver { fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); - fn add_ext(&mut self, ident: ast::Ident, ext: Rc); - fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + fn add_builtin(&mut self, ident: ast::Ident, ext: Rc); fn resolve_imports(&mut self); // Resolves attribute and derive legacy macros from `#![plugin(..)]`. fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, - force: bool) -> Result, Determinacy>; + fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) + -> Result>, Determinacy>; + fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) + -> Result, Determinacy>; } #[derive(Copy, Clone, Debug)] @@ -577,11 +578,14 @@ impl Resolver for DummyResolver { fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} - fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} - fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + fn add_builtin(&mut self, _ident: ast::Ident, _ext: Rc) {} fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) + -> Result>, Determinacy> { + Err(Determinacy::Determined) + } fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind, _force: bool) -> Result, Determinacy> { Err(Determinacy::Determined) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f8d4eff80b2d1..e0fb46ff5eb09 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,11 +38,11 @@ pub trait AstBuilder { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -323,7 +323,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment::crate_root()); } - segments.extend(idents.into_iter().map(Into::into)); + segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp))); let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { None } else { @@ -333,7 +333,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }))) }; - segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); + segments.push(ast::PathSegment { + identifier: last_identifier, + span: sp, + parameters: parameters + }); ast::Path { span: sp, segments: segments, @@ -346,7 +350,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path) { self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } @@ -357,7 +361,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -369,7 +373,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }; path.segments.push(ast::PathSegment { - identifier: ident, + identifier: ident.node, + span: ident.span, parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1662284a8820..10168f010a077 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -154,7 +154,7 @@ impl ExpansionKind { pub struct Invocation { pub kind: InvocationKind, expansion_kind: ExpansionKind, - expansion_data: ExpansionData, + pub expansion_data: ExpansionData, } pub enum InvocationKind { @@ -251,7 +251,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; - let ext = match self.resolve_invoc(&mut invoc, scope, force) { + let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { @@ -364,64 +364,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } - fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) - -> Result>, Determinacy> { - let (attr, traits, item) = match invoc.kind { - InvocationKind::Bang { ref mac, .. } => { - return self.cx.resolver.resolve_macro(scope, &mac.node.path, - MacroKind::Bang, force).map(Some); - } - InvocationKind::Attr { attr: None, .. } => return Ok(None), - InvocationKind::Derive { name, span, .. } => { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.cx.resolver.resolve_macro(scope, &path, - MacroKind::Derive, force).map(Some) - } - InvocationKind::Attr { ref mut attr, ref traits, ref mut item } => (attr, traits, item), - }; - - let (attr_name, path) = { - let attr = attr.as_ref().unwrap(); - (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) - }; - - let mut determined = true; - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Attr, force) { - Ok(ext) => return Ok(Some(ext)), - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), - _ => {} - } - - for &(name, span) in traits { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - match self.cx.resolver.resolve_macro(scope, &path, MacroKind::Derive, force) { - Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { - if inert_attrs.contains(&attr_name) { - // FIXME(jseyfried) Avoid `mem::replace` here. - let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) - .make_items().pop().unwrap(); - *item = mem::replace(item, Annotatable::Item(dummy_item)) - .map_attrs(|mut attrs| { - let inert_attr = attr.take().unwrap(); - attr::mark_known(&inert_attr); - if self.cx.ecfg.proc_macro_enabled() { - *attr = find_attr_invoc(&mut attrs); - } - attrs.push(inert_attr); - attrs - }); - } - return Err(Determinacy::Undetermined); - }, - Err(Determinacy::Undetermined) => determined = false, - Err(Determinacy::Determined) => {} - } - } - - Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) - } - fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), @@ -464,8 +406,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); let item_toks = stream_for_item(&item, &self.cx.parse_sess); + let span = Span { + expn_id: self.cx.codemap().record_expansion(ExpnInfo { + call_site: attr.span, + callee: NameAndSpan { + format: MacroAttribute(name), + span: None, + allow_internal_unstable: false, + }, + }), + ..attr.span + }; + let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); - self.parse_expansion(tok_result, kind, name, attr.span) + self.parse_expansion(tok_result, kind, name, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); @@ -490,7 +444,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = mark_tts(mac.node.stream(), mark); + let marked_tts = + noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -802,7 +757,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } } -fn find_attr_invoc(attrs: &mut Vec) -> Option { +pub fn find_attr_invoc(attrs: &mut Vec) -> Option { for i in 0 .. attrs.len() { if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) { return Some(attrs.remove(i)); @@ -948,17 +903,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::ItemKind::Mac(..) => { self.check_attributes(&item.attrs); - let is_macro_def = if let ItemKind::Mac(ref mac) = item.node { - mac.node.path.segments[0].identifier.name == "macro_rules" - } else { - unreachable!() - }; - - item.and_then(|mut item| match item.node { - ItemKind::Mac(_) if is_macro_def => { - item.id = Mark::fresh().as_placeholder_id(); - SmallVector::one(P(item)) - } + item.and_then(|item| match item.node { ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, @@ -1078,7 +1023,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - noop_fold_item_kind(self.cfg.configure_item_kind(item), self) + match item { + ast::ItemKind::MacroDef(..) => item, + _ => noop_fold_item_kind(self.cfg.configure_item_kind(item), self), + } } fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { @@ -1159,8 +1107,3 @@ impl Folder for Marker { span } } - -// apply a given mark to the given token trees. Used prior to expansion of a macro. -pub fn mark_tts(tts: TokenStream, m: Mark) -> TokenStream { - noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) -} diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 2af5c2ea9995e..57f5ab73d3706 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -31,7 +31,7 @@ pub struct SyntaxContextData { } /// A mark is a unique id associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)] pub struct Mark(u32); impl Mark { @@ -118,13 +118,6 @@ impl SyntaxContext { }) }) } - - /// If `ident` is macro expanded, return the source ident from the macro definition - /// and the mark of the expansion that created the macro definition. - pub fn source(self) -> (Self /* source context */, Mark /* source macro */) { - let macro_def_ctxt = self.data().prev_ctxt.data(); - (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark) - } } impl fmt::Debug for SyntaxContext { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index e2fb1946e90db..f60b1d17a5e2f 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -21,7 +21,6 @@ use util::move_map::MoveMap; use util::small_vector::SmallVector; use std::collections::HashMap; -use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { @@ -174,20 +173,11 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_block(&mut self, block: P) -> P { noop_fold_block(block, self).map(|mut block| { - let mut macros = Vec::new(); let mut remaining_stmts = block.stmts.len(); block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - // `macro_rules!` macro definition - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(_) = item.node { - macros.push(Mark::from_placeholder_id(item.id)); - return None; - } - } - match stmt.node { // Avoid wasting a node id on a trailing expression statement, // which shares a HIR node with the expression itself. @@ -201,11 +191,6 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { _ => {} } - if self.monotonic && !macros.is_empty() { - let macros = mem::replace(&mut macros, Vec::new()); - self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); - } - Some(stmt) }); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1d386c1a3ac93..7aa1230f9aeea 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -153,7 +153,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // Holy self-referential! /// Converts a `macro_rules!` invocation into a syntax extension. -pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { +pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension { let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); @@ -183,7 +183,11 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { ]; // Parse the macro_rules! invocation - let argument_map = match parse(sess, def.body.clone().into(), &argument_gram, None) { + let body = match def.node { + ast::ItemKind::MacroDef(ref body) => body.clone().into(), + _ => unreachable!(), + }; + let argument_map = match parse(sess, body, &argument_gram, None) { Success(m) => m, Failure(sp, tok) => { let s = parse_failure_msg(tok); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9ee6..9269673b40c65 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,12 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Allows the `catch {...}` expression + (active, catch_expr, "1.17.0", Some(31436)), + + // Used to preserve symbols + (active, used, "1.17.0", Some(40289)), ); declare_features! ( @@ -742,6 +748,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, @@ -1287,6 +1297,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + ast::ExprKind::Catch(_) => { + gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b9803..9f11d0173d6d5 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -434,8 +434,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { + segments: segments.move_map(|PathSegment {identifier, span, parameters}| PathSegment { identifier: fld.fold_ident(identifier), + span: fld.new_span(span), parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) @@ -899,6 +900,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { items.move_flat_map(|item| folder.fold_trait_item(item)), ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), + ItemKind::MacroDef(tts) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into()), } } @@ -959,7 +961,7 @@ pub fn noop_fold_mod(Mod {inner, items}: Mod, folder: &mut T) -> Mod } } -pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, span}: Crate, +pub fn noop_fold_crate(Crate {module, attrs, span}: Crate, folder: &mut T) -> Crate { let mut items = folder.fold_item(P(ast::Item { ident: keywords::Invalid.ident(), @@ -987,14 +989,9 @@ pub fn noop_fold_crate(Crate {module, attrs, mut exported_macros, spa }, vec![], span) }; - for def in &mut exported_macros { - def.id = folder.new_id(def.id); - } - Crate { module: module, attrs: attrs, - exported_macros: exported_macros, span: span, } } @@ -1272,6 +1269,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), + ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, id: folder.new_id(id), span: folder.new_span(span), @@ -1387,6 +1385,6 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); + "macro_rules! zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)));".to_string()); } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b42..88535f91379f7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -617,13 +617,17 @@ mod tests { Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} } + fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { + ast::PathSegment::from_ident(Ident::from_str(s), sp(lo, hi)) + } + #[test] fn path_exprs_1() { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - segments: vec![Ident::from_str("a").into()], + segments: vec![str2seg("a", 0, 1)], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -637,8 +641,8 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), segments: vec![ast::PathSegment::crate_root(), - Ident::from_str("a").into(), - Ident::from_str("b").into()] + str2seg("a", 2, 3), + str2seg("b", 5, 6)] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -744,7 +748,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - segments: vec![Ident::from_str("d").into()], + segments: vec![str2seg("d", 7, 8)], }), span:sp(7,8), attrs: ThinVec::new(), @@ -761,7 +765,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 0, 1)], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -802,7 +806,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - segments: vec![Ident::from_str("i32").into()], + segments: vec![str2seg("i32", 10, 13)], }), span:sp(10,13) }), @@ -844,7 +848,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 17, 18)], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d606..8f66c1a2b8cf6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use ast::Local; use ast::MacStmtStyle; use ast::Mac_; use ast::{MutTy, Mutability}; -use ast::{Pat, PatKind}; +use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; @@ -1048,7 +1048,7 @@ impl<'a> Parser<'a> { self.expected_tokens.clear(); } - pub fn look_ahead(&mut self, dist: usize, f: F) -> R where + pub fn look_ahead(&self, dist: usize, f: F) -> R where F: FnOnce(&token::Token) -> R, { if dist == 0 { @@ -1811,7 +1811,7 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, ast::PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root()); } // Assemble the span. @@ -1829,11 +1829,12 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1881,7 +1882,11 @@ impl<'a> Parser<'a> { }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); + segments.push(PathSegment { + identifier: identifier, + span: ident_span, + parameters: parameters + }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1892,15 +1897,16 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); return Ok(segments); } @@ -1909,8 +1915,9 @@ impl<'a> Parser<'a> { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; - segments.push(ast::PathSegment { + segments.push(PathSegment { identifier: identifier, + span: ident_span, parameters: ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1924,7 +1931,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); } } } @@ -1932,14 +1939,14 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` pub fn parse_path_segments_without_types(&mut self) - -> PResult<'a, Vec> { + -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, self.prev_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -2273,6 +2280,12 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span.lo; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3092,6 +3105,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } + /// Parse a `do catch {...}` expression (`do catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + -> PResult<'a, P> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + let hi = body.span.hi; + Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + } + // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; @@ -3699,11 +3722,50 @@ impl<'a> Parser<'a> { }) } - fn is_union_item(&mut self) -> bool { + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) + } + + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) } + fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) + -> PResult<'a, Option>> { + let lo = self.span.lo; + match self.token { + token::Ident(ident) if ident.name == "macro_rules" => { + if self.look_ahead(1, |t| *t == token::Not) { + let prev_span = self.prev_span; + self.complain_if_pub_macro(vis, prev_span); + self.bump(); + self.bump(); + } + } + _ => return Ok(None), + }; + + let id = self.parse_ident()?; + let (delim, tts) = self.expect_delimited_token_tree()?; + if delim != token::Brace { + if !self.eat(&token::Semi) { + let msg = "macros that expand to items must either be surrounded with braces \ + or followed by a semicolon"; + self.span_err(self.prev_span, msg); + } + } + + let hi = self.prev_span.hi; + let kind = ItemKind::MacroDef(tts); + Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + } + fn parse_stmt_without_recovery(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option> { @@ -3718,6 +3780,12 @@ impl<'a> Parser<'a> { node: StmtKind::Local(self.parse_local(attrs.into())?), span: mk_sp(lo, self.prev_span.hi), } + } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { + Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Item(macro_def), + span: mk_sp(lo, self.prev_span.hi), + } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && !self.token.is_qpath_start() && @@ -4605,7 +4673,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4839,6 +4907,7 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4888,6 +4957,7 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -4936,7 +5006,7 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility(false)?; + let mut vis = p.parse_visibility()?; let ty_is_interpolated = p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); let mut ty = p.parse_ty()?; @@ -4993,38 +5063,46 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; self.parse_single_struct_field(lo, vis, attrs) } - // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) - fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { - let pub_crate = |this: &mut Self| { - let span = this.prev_span; - this.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Crate(span)) - }; - + // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts + // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. + fn parse_visibility(&mut self) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { - Ok(Visibility::Inherited) - } else if !allow_path { - // Look ahead to avoid eating the `(` in `pub(path)` while still parsing `pub(crate)` - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { - self.bump(); self.bump(); - pub_crate(self) - } else { - Ok(Visibility::Public) - } - } else if !self.eat(&token::OpenDelim(token::Paren)) { - Ok(Visibility::Public) - } else if self.eat_keyword(keywords::Crate) { - pub_crate(self) - } else { - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); - self.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) - } + return Ok(Visibility::Inherited) + } + + if self.check(&token::OpenDelim(token::Paren)) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { + // `pub(crate)` + self.bump(); // `(` + self.bump(); // `crate` + let vis = Visibility::Crate(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { + // `pub(in path)` + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && + self.look_ahead(1, |t| t.is_keyword(keywords::Super) || + t.is_keyword(keywords::SelfValue)) { + // `pub(self)` or `pub(super)` + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } + } + + Ok(Visibility::Public) } /// Parse defaultness: DEFAULT or nothing @@ -5499,7 +5577,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5767,6 +5845,10 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if let Some(macro_def) = self.eat_macro_def(&attrs, &visibility)? { + return Ok(Some(macro_def)); + } + self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) } @@ -5774,7 +5856,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM @@ -5902,7 +5984,7 @@ impl<'a> Parser<'a> { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![ast::PathSegment::crate_root()], + segments: vec![PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { @@ -5948,7 +6030,6 @@ impl<'a> Parser<'a> { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, span: mk_sp(lo, self.span.lo), - exported_macros: Vec::new(), }) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b81c..25601f2420e8a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -86,6 +86,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 53ef8e8dfa49c..c44153d0d3245 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1318,7 +1318,6 @@ impl<'a> State<'a> { self.bclose(item.span)?; } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { - self.print_visibility(&item.vis)?; self.print_path(&node.path, false, 0, false)?; word(&mut self.s, "! ")?; self.print_ident(item.ident)?; @@ -1329,6 +1328,16 @@ impl<'a> State<'a> { word(&mut self.s, ";")?; self.end()?; } + ast::ItemKind::MacroDef(ref tts) => { + word(&mut self.s, "macro_rules! ")?; + self.print_ident(item.ident)?; + self.cbox(INDENT_UNIT)?; + self.popen()?; + self.print_tts(tts.clone().into())?; + self.pclose()?; + word(&mut self.s, ";")?; + self.end()?; + } } self.ann.post(self, NodeItem(item)) } @@ -2270,6 +2279,11 @@ impl<'a> State<'a> { self.print_expr(e)?; word(&mut self.s, "?")? } + ast::ExprKind::Catch(ref blk) => { + self.head("catch")?; + space(&mut self.s)?; + self.print_block_with_attrs(&blk, attrs)? + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf61247c..2192d203cdc23 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -82,7 +82,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { - ast::Ident::from_str(name).into() + ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP) }).collect(), span: span, })))), diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c278171aa109a..6642c60d256b3 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,9 +221,10 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + (56, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (56, CrateRoot, "{{root}}") + (57, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dd2756cd2b22c..e052d2cda3a42 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,7 +580,7 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - segments: ids.into_iter().map(Into::into).collect(), + segments: ids.into_iter().map(|id| ast::PathSegment::from_ident(id, DUMMY_SP)).collect(), } } diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index b90802d1e7eb8..9d9957a0f4534 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -148,9 +148,4 @@ impl<'ast> Visitor<'ast> for NodeCounter { fn visit_attribute(&mut self, _attr: &Attribute) { self.count += 1; } - fn visit_macro_def(&mut self, macro_def: &MacroDef) { - self.count += 1; - walk_macro_def(self, macro_def) - } - } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 013632141dee6..a5333f3bb6a6e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -125,9 +125,6 @@ pub trait Visitor<'ast>: Sized { walk_assoc_type_binding(self, type_binding) } fn visit_attribute(&mut self, _attr: &'ast Attribute) {} - fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) { - walk_macro_def(self, macro_def) - } fn visit_vis(&mut self, vis: &'ast Visibility) { walk_vis(self, vis) } @@ -176,12 +173,6 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, span: Span, ident: Ident) pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID); walk_list!(visitor, visit_attribute, &krate.attrs); - walk_list!(visitor, visit_macro_def, &krate.exported_macros); -} - -pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) { - visitor.visit_ident(macro_def.span, macro_def.ident); - walk_list!(visitor, visit_attribute, ¯o_def.attrs); } pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) { @@ -295,6 +286,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_trait_item, methods); } ItemKind::Mac(ref mac) => visitor.visit_mac(mac), + ItemKind::MacroDef(..) => {}, } walk_list!(visitor, visit_attribute, &item.attrs); } @@ -787,6 +779,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::Catch(ref body) => { + visitor.visit_block(body) + } } visitor.visit_expr_post(expression) diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 960db792a623e..bdcec26cb838b 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } -log = { path = "../liblog" } +log = "0.3" proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1fc1bdff593c2..dc4b8eb24cd0a 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - segments: vec![self.ident.into()], + segments: vec![ast::PathSegment::from_ident(self.ident, self.span)], } } } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 3bceb02f3d6c5..b51591bf89d5e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -99,7 +99,7 @@ macro_rules! derive_traits { pub fn register_builtin_derives(resolver: &mut Resolver) { $( - resolver.add_ext( + resolver.add_builtin( ast::Ident::with_empty_ctxt(Symbol::intern($name)), Rc::new(SyntaxExtension::BuiltinDerive($func)) ); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index f92cde4019f67..1e9b112b6df56 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -59,7 +59,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, deriving::register_builtin_derives(resolver); let mut register = |name, ext| { - resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); + resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; macro_rules! register { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 9c96ad547e1ae..5adaf470f2374 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -90,12 +90,7 @@ pub fn modify(sess: &ParseSess, krate.module.items.push(mk_registrar(&mut cx, &derives, &attr_macros, &bang_macros)); - if krate.exported_macros.len() > 0 { - handler.err("cannot export macro_rules! macros from a `proc-macro` \ - crate type currently"); - } - - return krate + krate } fn is_proc_macro_attr(attr: &ast::Attribute) -> bool { @@ -251,6 +246,15 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { + if let ast::ItemKind::MacroDef(..) = item.node { + if self.is_proc_macro_crate && + item.attrs.iter().any(|attr| attr.name() == "macro_export") { + let msg = + "cannot export macro_rules! macros from a `proc-macro` crate type currently"; + self.handler.span_err(item.span, msg); + } + } + // First up, make sure we're checking a bare function. If we're not then // we're just not interested in this item. // diff --git a/src/llvm b/src/llvm index 50ab09fb43f03..859fb26936462 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 50ab09fb43f038e4f824eea6cb278f560d3e8621 +Subproject commit 859fb269364623b17e092efaba3f94e70ce97c5e diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-rebuild-trigger similarity index 61% rename from src/rustllvm/llvm-auto-clean-trigger rename to src/rustllvm/llvm-rebuild-trigger index 57f37ea050c1b..aeabf4a1dd376 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ -# If this file is modified, then llvm will be forcibly cleaned and then rebuilt. +# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-03-02 +2017-03-04 diff --git a/src/stage0.txt b/src/stage0.txt index cda9a5a96432b..772029ab0c253 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -13,4 +13,4 @@ # released on `$date` rustc: beta-2017-02-01 -cargo: bfee18f73287687c543bda8c35e4e33808792715 +cargo: 407edef22e894266eb562618cba5ca9757051946 diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs index 9de74f72005e3..9883ca6b35d04 100644 --- a/src/test/codegen/naked-functions.rs +++ b/src/test/codegen/naked-functions.rs @@ -20,7 +20,8 @@ #[no_mangle] #[naked] fn naked_empty() { - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret void } // CHECK: Function Attrs: naked uwtable @@ -28,9 +29,10 @@ fn naked_empty() { #[naked] // CHECK-NEXT: define internal void @naked_with_args(i{{[0-9]+}}) fn naked_with_args(a: isize) { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret void + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret void } // CHECK: Function Attrs: naked uwtable @@ -38,7 +40,8 @@ fn naked_with_args(a: isize) { #[no_mangle] #[naked] fn naked_with_return() -> isize { - // CHECK: ret i{{[0-9]+}} 0 + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: ret i{{[0-9]+}} 0 0 } @@ -47,9 +50,10 @@ fn naked_with_return() -> isize { #[no_mangle] #[naked] fn naked_with_args_and_return(a: isize) -> isize { - // CHECK: %a = alloca i{{[0-9]+}} - // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: %a = alloca i{{[0-9]+}} &a; // keep variable in an alloca + // CHECK: ret i{{[0-9]+}} %{{[0-9]+}} a } @@ -58,14 +62,37 @@ fn naked_with_args_and_return(a: isize) -> isize { #[no_mangle] #[naked] fn naked_recursive() { - // CHECK: call void @naked_empty() + // CHECK-NEXT: {{.+}}: + // CHECK-NEXT: call void @naked_empty() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb1 + // CHECK: bb1: + naked_empty(); - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_return() + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb2 + // CHECK: bb2: + + // CHECK-NEXT: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb3 + // CHECK: bb3: + + // CHECK-NEXT: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) + + // FIXME(#39685) Avoid one block per call. + // CHECK-NEXT: br label %bb4 + // CHECK: bb4: + naked_with_args( - // CHECK: %{{[0-9]+}} = call i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+}} %{{[0-9]+}}) naked_with_args_and_return( - // CHECK: call void @naked_with_args(i{{[0-9]+}} %{{[0-9]+}}) naked_with_return() ) ); + // CHECK-NEXT: ret void } diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index db2cd3b41656d..4bd471d05c711 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -27,3 +27,36 @@ pub fn write_pkd(pkd: &mut Packed) -> u32 { pkd.data = 42; result } + +pub struct Array([i32; 8]); +#[repr(packed)] +pub struct BigPacked { + dealign: u8, + data: Array +} + +// CHECK-LABEL: @call_pkd +#[no_mangle] +pub fn call_pkd(f: fn() -> Array) -> BigPacked { +// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array +// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 32, i32 1, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked { dealign: 0, data: f() } +} + +#[repr(packed)] +#[derive(Copy, Clone)] +pub struct PackedPair(u8, u32); + +// CHECK-LABEL: @pkd_pair +#[no_mangle] +pub fn pkd_pair(pair1: &mut PackedPair, pair2: &mut PackedPair) { + // CHECK: [[V1:%[a-z0-9]+]] = load i8, i8* %{{.*}}, align 1 + // CHECK: [[V2:%[a-z0-9]+]] = load i32, i32* %{{.*}}, align 1 + // CHECK: store i8 [[V1]], i8* {{.*}}, align 1 + // CHECK: store i32 [[V2]], i32* {{.*}}, align 1 + *pair2 = *pair1; +} diff --git a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs index 9dc4cf1252ec3..6f458da9b527b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/pub_and_stability.rs @@ -55,7 +55,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) b_crate: i32, #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) c_mod: i32, + pub(in m) c_mod: i32, #[stable(feature = "unit_test", since = "0.0.0")] // SILLY d_priv: i32 } @@ -71,7 +71,7 @@ mod m { pub i32, pub(crate) i32, - pub(m) i32, + pub(in m) i32, i32); impl Record { @@ -124,7 +124,7 @@ mod m { #[unstable(feature = "unstable_undeclared", issue = "38412")] // SILLY pub(crate) fn pub_crate(&self) -> i32 { self.d_priv } #[unstable(feature = "unstable_declared", issue = "38412")] // SILLY - pub(m) fn pub_mod(&self) -> i32 { self.d_priv } + pub(in m) fn pub_mod(&self) -> i32 { self.d_priv } #[stable(feature = "unit_test", since = "0.0.0")] // SILLY fn private(&self) -> i32 { self.d_priv } } @@ -138,7 +138,7 @@ mod m { pub fn stable(&self) -> i32 { self.0 } pub(crate) fn pub_crate(&self) -> i32 { self.0 } - pub(m) fn pub_mod(&self) -> i32 { self.0 } + pub(in m) fn pub_mod(&self) -> i32 { self.0 } fn private(&self) -> i32 { self.0 } } } diff --git a/src/test/compile-fail/catch-in-match.rs b/src/test/compile-fail/catch-in-match.rs new file mode 100644 index 0000000000000..9f9968e81242a --- /dev/null +++ b/src/test/compile-fail/catch-in-match.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +fn main() { + match do catch { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `do` +} diff --git a/src/test/compile-fail/catch-in-while.rs b/src/test/compile-fail/catch-in-while.rs new file mode 100644 index 0000000000000..cb8613ee60b42 --- /dev/null +++ b/src/test/compile-fail/catch-in-while.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +fn main() { + while do catch { false } {} //~ ERROR expected expression, found reserved keyword `do` +} diff --git a/src/test/run-pass-fulldeps/mir-pass.rs b/src/test/compile-fail/feature-gate-catch_expr.rs similarity index 65% rename from src/test/run-pass-fulldeps/mir-pass.rs rename to src/test/compile-fail/feature-gate-catch_expr.rs index 8ac4bf9733757..5568a5cf0aac2 100644 --- a/src/test/run-pass-fulldeps/mir-pass.rs +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,16 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:dummy_mir_pass.rs -// ignore-stage1 - -#![feature(plugin)] -#![plugin(dummy_mir_pass)] - -fn math() -> i32 { - 11 -} - pub fn main() { - assert_eq!(math(), 42); + let catch_result = do catch { //~ ERROR `catch` expression is experimental + let x = 5; + x + }; + assert_eq!(catch_result, 5); } diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs new file mode 100644 index 0000000000000..68679d7dac896 --- /dev/null +++ b/src/test/compile-fail/feature-gate-used.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[used] +fn foo() {} +//~^^ ERROR the `#[used]` attribute is an experimental feature + +fn main() {} diff --git a/src/test/compile-fail/issue-40288-2.rs b/src/test/compile-fail/issue-40288-2.rs new file mode 100644 index 0000000000000..c1e8cb8b6defb --- /dev/null +++ b/src/test/compile-fail/issue-40288-2.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn prove_static(_: &'static T) {} + +fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = [x]; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let slice: &mut [_] = &mut out; + slice[0] = y; + } + out[0] +} + +struct Struct { + head: T, + _tail: U +} + +fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { + let mut out = Struct { head: x, _tail: [()] }; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + { + let dst: &mut Struct<_, [()]> = &mut out; + dst.head = y; + } + out.head +} + +fn main() { + prove_static(lifetime_transmute_slice("", &String::from("foo"))); + prove_static(lifetime_transmute_struct("", &String::from("bar"))); +} diff --git a/src/test/compile-fail/issue-40288.rs b/src/test/compile-fail/issue-40288.rs new file mode 100644 index 0000000000000..b5418e85bec78 --- /dev/null +++ b/src/test/compile-fail/issue-40288.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn save_ref<'a>(refr: &'a i32, to: &mut [&'a i32]) { + for val in &mut *to { + *val = refr; + } +} + +fn main() { + let ref init = 0i32; + let ref mut refr = 1i32; + + let mut out = [init]; + + save_ref(&*refr, &mut out); + + // This shouldn't be allowed as `refr` is borrowed + *refr = 3; //~ ERROR cannot assign to `*refr` because it is borrowed + + // Prints 3?! + println!("{:?}", out[0]); +} diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index fb75b9aa1dd94..e37b6a2bb9c99 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -79,7 +79,7 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR lifetime bound not satisfied + //~^ ERROR cannot infer //~| ERROR cannot infer } diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index dd94dfe1e0823..c0dd5200f6cb4 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR lifetime bound not satisfied + ss.r //~ ERROR cannot infer an appropriate lifetime } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR lifetime bound not satisfied + ss.r = b; //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs index 4e2a69cb79e19..2d4b5545544c6 100644 --- a/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs +++ b/src/test/compile-fail/privacy/restricted/lookup-ignores-private.rs @@ -16,10 +16,10 @@ mod foo { mod bar { #[derive(Default)] pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } impl S { - pub(foo) fn f(&self) -> i32 { 0 } + pub(in foo) fn f(&self) -> i32 { 0 } } pub struct S2 { diff --git a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs index e254e005656c1..53786d45c73ee 100644 --- a/src/test/compile-fail/privacy/restricted/struct-literal-field.rs +++ b/src/test/compile-fail/privacy/restricted/struct-literal-field.rs @@ -15,7 +15,7 @@ mod foo { pub mod bar { pub struct S { - pub(foo) x: i32, + pub(in foo) x: i32, } } diff --git a/src/test/compile-fail/privacy/restricted/test.rs b/src/test/compile-fail/privacy/restricted/test.rs index 01e2c6cd7e828..d55ee8221cd73 100644 --- a/src/test/compile-fail/privacy/restricted/test.rs +++ b/src/test/compile-fail/privacy/restricted/test.rs @@ -57,6 +57,6 @@ fn main() { } mod pathological { - pub(bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? - pub(foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules + pub(in bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`? + pub(in foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules } diff --git a/src/test/compile-fail/privacy/restricted/ty-params.rs b/src/test/compile-fail/privacy/restricted/ty-params.rs index da7086cf554c3..cd0edc8fe7c44 100644 --- a/src/test/compile-fail/privacy/restricted/ty-params.rs +++ b/src/test/compile-fail/privacy/restricted/ty-params.rs @@ -11,16 +11,11 @@ #![feature(pub_restricted)] macro_rules! m { - ($p: path) => (pub($p) struct Z;) + ($p: path) => (pub(in $p) struct Z;) } struct S(T); m!{ S } //~ ERROR type or lifetime parameters in visibility path //~^ ERROR expected module, found struct `S` -mod foo { - struct S(pub(foo) ()); //~ ERROR type or lifetime parameters in visibility path - //~^ ERROR cannot find type `T` in this scope -} - fn main() {} diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index c5cf43e355d5a..ad6c5a31bbbd3 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR lifetime bound not satisfied + box v as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index fb726e31af586..17fd55b031b61 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -16,7 +16,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - Box::new(move|| { *x }) //~ ERROR does not fulfill the required lifetime + Box::new(move|| { *x }) //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index b4e527972e476..e8ada6a175571 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,8 +22,8 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR lifetime bound not satisfied - //~^ ERROR cannot infer + x //~ ERROR cannot infer an appropriate lifetime + //~^ ERROR cannot infer an appropriate lifetime } struct Wrapper(T); diff --git a/src/test/compile-fail/resolve-bad-visibility.rs b/src/test/compile-fail/resolve-bad-visibility.rs index 6b5cd4dce265a..20878a91ede99 100644 --- a/src/test/compile-fail/resolve-bad-visibility.rs +++ b/src/test/compile-fail/resolve-bad-visibility.rs @@ -13,11 +13,11 @@ enum E {} trait Tr {} -pub(E) struct S; //~ ERROR expected module, found enum `E` -pub(Tr) struct Z; //~ ERROR expected module, found trait `Tr` -pub(std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules -pub(nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root -pub(too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root +pub(in E) struct S; //~ ERROR expected module, found enum `E` +pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` +pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules +pub(in nonexistent) struct G; //~ ERROR cannot find module `nonexistent` in the crate root +pub(in too_soon) struct H; //~ ERROR cannot find module `too_soon` in the crate root // Visibilities are resolved eagerly without waiting for modules becoming fully populated. // Visibilities can only use ancestor modules legally which are always available in time, diff --git a/src/test/compile-fail/variance-contravariant-arg-object.rs b/src/test/compile-fail/variance-contravariant-arg-object.rs index 1795ac95358d7..d3bf92e85f411 100644 --- a/src/test/compile-fail/variance-contravariant-arg-object.rs +++ b/src/test/compile-fail/variance-contravariant-arg-object.rs @@ -21,7 +21,7 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) @@ -29,7 +29,7 @@ fn get_max_from_min<'min, 'max, G>(v: Box>) where 'max : 'min { // Previously OK: - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-covariant-arg-object.rs b/src/test/compile-fail/variance-covariant-arg-object.rs index ad059a467f570..0e94e35df2839 100644 --- a/src/test/compile-fail/variance-covariant-arg-object.rs +++ b/src/test/compile-fail/variance-covariant-arg-object.rs @@ -22,14 +22,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) where 'max : 'min { // Previously OK, now an error as traits are invariant. - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/compile-fail/variance-invariant-arg-object.rs b/src/test/compile-fail/variance-invariant-arg-object.rs index 9edb510b826a1..aa3e06c015d50 100644 --- a/src/test/compile-fail/variance-invariant-arg-object.rs +++ b/src/test/compile-fail/variance-invariant-arg-object.rs @@ -18,14 +18,14 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v //~ ERROR mismatched types + v //~ ERROR cannot infer an appropriate lifetime } fn main() { } diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 2452c18f54347..900b0829530f3 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -15,31 +15,38 @@ // === GDB TESTS =================================================================================== -// gdb-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbg-command:print 'c_style_enum::SINGLE_VARIANT' +// gdbr-command:print c_style_enum::SINGLE_VARIANT // gdbg-check:$1 = TheOnlyVariant // gdbr-check:$1 = c_style_enum::SingleVariant::TheOnlyVariant -// gdb-command:print 'c_style_enum::AUTO_ONE' +// gdbg-command:print 'c_style_enum::AUTO_ONE' +// gdbr-command:print c_style_enum::AUTO_ONE // gdbg-check:$2 = One // gdbr-check:$2 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_TWO' +// gdbg-command:print 'c_style_enum::AUTO_TWO' +// gdbr-command:print c_style_enum::AUTO_TWO // gdbg-check:$3 = One // gdbr-check:$3 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::AUTO_THREE' +// gdbg-command:print 'c_style_enum::AUTO_THREE' +// gdbr-command:print c_style_enum::AUTO_THREE // gdbg-check:$4 = One // gdbr-check:$4 = c_style_enum::AutoDiscriminant::One -// gdb-command:print 'c_style_enum::MANUAL_ONE' +// gdbg-command:print 'c_style_enum::MANUAL_ONE' +// gdbr-command:print c_style_enum::MANUAL_ONE // gdbg-check:$5 = OneHundred // gdbr-check:$5 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_TWO' +// gdbg-command:print 'c_style_enum::MANUAL_TWO' +// gdbr-command:print c_style_enum::MANUAL_TWO // gdbg-check:$6 = OneHundred // gdbr-check:$6 = c_style_enum::ManualDiscriminant::OneHundred -// gdb-command:print 'c_style_enum::MANUAL_THREE' +// gdbg-command:print 'c_style_enum::MANUAL_THREE' +// gdbr-command:print c_style_enum::MANUAL_THREE // gdbg-check:$7 = OneHundred // gdbr-check:$7 = c_style_enum::ManualDiscriminant::OneHundred diff --git a/src/test/debuginfo/limited-debuginfo.rs b/src/test/debuginfo/limited-debuginfo.rs index 3d21def3953b8..e8c3597b8c8dd 100644 --- a/src/test/debuginfo/limited-debuginfo.rs +++ b/src/test/debuginfo/limited-debuginfo.rs @@ -15,10 +15,14 @@ // Make sure functions have proper names // gdb-command:info functions -// gdb-check:[...]void[...]main([...]); -// gdb-check:[...]void[...]some_function([...]); -// gdb-check:[...]void[...]some_other_function([...]); -// gdb-check:[...]void[...]zzz([...]); +// gdbg-check:[...]void[...]main([...]); +// gdbr-check:fn limited_debuginfo::main(); +// gdbg-check:[...]void[...]some_function([...]); +// gdbr-check:fn limited_debuginfo::some_function(); +// gdbg-check:[...]void[...]some_other_function([...]); +// gdbr-check:fn limited_debuginfo::some_other_function(); +// gdbg-check:[...]void[...]zzz([...]); +// gdbr-check:fn limited_debuginfo::zzz(); // gdb-command:run diff --git a/src/test/debuginfo/simple-struct.rs b/src/test/debuginfo/simple-struct.rs index 4956313ad2214..ae05bafe5adaa 100644 --- a/src/test/debuginfo/simple-struct.rs +++ b/src/test/debuginfo/simple-struct.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print 'simple_struct::NO_PADDING_16' // gdbr-command:print simple_struct::NO_PADDING_16 // gdbg-check:$1 = {x = 1000, y = -1001} diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 354a2c26cb36d..b3c2704115095 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -14,9 +14,6 @@ // === GDB TESTS =================================================================================== -// there's no frame yet for gdb to reliably detect the language, set it explicitly -// gdbr-command:set language rust - // gdbg-command:print/d 'simple_tuple::NO_PADDING_8' // gdbr-command:print simple_tuple::NO_PADDING_8 // gdbg-check:$1 = {__0 = -50, __1 = 50} diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 1d452907cf59a..fbbffe8953b38 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -35,7 +35,6 @@ fn main() { // } // // bb2: { -// StorageLive(_6); // _0 = (); // StorageDead(_4); // StorageDead(_1); diff --git a/src/test/run-make/dep-info-doesnt-run-much/Makefile b/src/test/run-make/dep-info-doesnt-run-much/Makefile new file mode 100644 index 0000000000000..2fd84639f2190 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + $(RUSTC) foo.rs --emit dep-info diff --git a/src/test/run-make/dep-info-doesnt-run-much/foo.rs b/src/test/run-make/dep-info-doesnt-run-much/foo.rs new file mode 100644 index 0000000000000..3591182104498 --- /dev/null +++ b/src/test/run-make/dep-info-doesnt-run-much/foo.rs @@ -0,0 +1,15 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// We're only emitting dep info, so we shouldn't be running static analysis to +// figure out that this program is erroneous. +fn main() { + let a: u8 = "a"; +} diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.rs b/src/test/run-make/extern-fn-with-packed-struct/test.rs index c0f55893a3abe..9e81636e36703 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/test.rs +++ b/src/test/run-make/extern-fn-with-packed-struct/test.rs @@ -8,14 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; + #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { a: i8, b: i16, c: i8 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.a == other.a && self.b == other.b && self.c == other.c + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let a = self.a; + let b = self.b; + let c = self.c; + + f.debug_struct("Foo") + .field("a", &a) + .field("b", &b) + .field("c", &c) + .finish() + } +} + #[link(name = "test", kind = "static")] extern { fn foo(f: Foo) -> Foo; diff --git a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs index 0717af98b30b4..3d2dd380e488e 100644 --- a/src/test/run-make/pretty-expanded-hygiene/input.pp.rs +++ b/src/test/run-make/pretty-expanded-hygiene/input.pp.rs @@ -12,6 +12,7 @@ #![feature(no_core)] #![no_core] +macro_rules! foo /* 60#0 */(( $ x : ident ) => { y + $ x }); fn bar /* 62#0 */() { let x /* 59#2 */ = 1; y /* 61#4 */ + x /* 59#5 */ } diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile new file mode 100644 index 0000000000000..650464e4d8454 --- /dev/null +++ b/src/test/run-make/used/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifdef IS_WINDOWS +# Do nothing on MSVC. +all: + exit 0 +else +all: + $(RUSTC) -C opt-level=3 --emit=obj used.rs + nm -C $(TMPDIR)/used.o | grep FOO + nm -C $(TMPDIR)/used.o | grep -v BAR +endif diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs new file mode 100644 index 0000000000000..186cd0fdf5e35 --- /dev/null +++ b/src/test/run-make/used/used.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#![feature(used)] + +#[used] +static FOO: u32 = 0; + +static BAR: u32 = 0; diff --git a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs b/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs deleted file mode 100644 index 3bc4a40a39c99..0000000000000 --- a/src/test/run-pass-fulldeps/auxiliary/dummy_mir_pass.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// force-host - -#![feature(plugin_registrar, rustc_private)] -#![feature(box_syntax)] - -#[macro_use] extern crate rustc; -extern crate rustc_plugin; -extern crate rustc_const_math; -extern crate syntax; - -use rustc::mir::transform::{self, MirPass, MirSource}; -use rustc::mir::{Mir, Literal, Location}; -use rustc::mir::visit::MutVisitor; -use rustc::ty::TyCtxt; -use rustc::middle::const_val::ConstVal; -use rustc_const_math::ConstInt; -use rustc_plugin::Registry; - -struct Pass; - -impl transform::Pass for Pass {} - -impl<'tcx> MirPass<'tcx> for Pass { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - Visitor.visit_mir(mir) - } -} - -struct Visitor; - -impl<'tcx> MutVisitor<'tcx> for Visitor { - fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) { - if let Literal::Value { ref mut value } = *literal { - if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value { - *i = 42; - } - } - } -} - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_mir_pass(box Pass); -} diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs new file mode 100644 index 0000000000000..a9b28a534a348 --- /dev/null +++ b/src/test/run-pass/catch-expr.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(catch_expr)] + +struct catch {} + +pub fn main() { + let catch_result = do catch { + let x = 5; + x + }; + assert_eq!(catch_result, 5); + + let mut catch = true; + while catch { catch = false; } + assert_eq!(catch, false); + + catch = if catch { false } else { true }; + assert_eq!(catch, true); + + match catch { + _ => {} + }; +} diff --git a/src/test/run-pass/coerce-unsize-subtype.rs b/src/test/run-pass/coerce-unsize-subtype.rs new file mode 100644 index 0000000000000..b19708f5a8931 --- /dev/null +++ b/src/test/run-pass/coerce-unsize-subtype.rs @@ -0,0 +1,48 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// pretty-expanded FIXME #23616 + +use std::rc::Rc; + +fn lub_short<'a, T>(_: &[&'a T], _: &[&'a T]) {} + +// The two arguments are a subtype of their LUB, after coercion. +fn long_and_short<'a, T>(xs: &[&'static T; 1], ys: &[&'a T; 1]) { + lub_short(xs, ys); +} + +// The argument coerces to a subtype of the return type. +fn long_to_short<'a, 'b, T>(xs: &'b [&'static T; 1]) -> &'b [&'a T] { + xs +} + +// Rc is covariant over T just like &T. +fn long_to_short_rc<'a, T>(xs: Rc<[&'static T; 1]>) -> Rc<[&'a T]> { + xs +} + +// LUB-coercion (if-else/match/array) coerces `xs: &'b [&'static T: N]` +// to a subtype of the LUB of `xs` and `ys` (i.e. `&'b [&'a T]`), +// regardless of the order they appear (in if-else/match/array). +fn long_and_short_lub1<'a, 'b, T>(xs: &'b [&'static T; 1], ys: &'b [&'a T]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +// LUB-coercion should also have the exact same effect when `&'b [&'a T; N]` +// needs to be coerced, i.e. the resulting type is not &'b [&'static T], but +// rather the `&'b [&'a T]` LUB. +fn long_and_short_lub2<'a, 'b, T>(xs: &'b [&'static T], ys: &'b [&'a T; 1]) { + let _order1 = [xs, ys]; + let _order2 = [ys, xs]; +} + +fn main() {} diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 4b32b881be738..57407b8422371 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -8,15 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::fmt; use std::mem; #[repr(packed)] -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone)] struct Foo { bar: u8, baz: u64 } +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + pub fn main() { let foos = [Foo { bar: 1, baz: 2 }; 10]; diff --git a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs index f190f5dd0534d..383224b2f9273 100644 --- a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -14,7 +14,7 @@ pub mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } } diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr index d541aa599a48b..dd04c5ce356c6 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -1,26 +1,26 @@ error[E0425]: cannot find value `A` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:15:13 + --> $DIR/enums-are-namespaced-xc.rs:15:31 | 15 | let _ = namespaced_enums::A; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::A;` error[E0425]: cannot find function `B` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:18:13 + --> $DIR/enums-are-namespaced-xc.rs:18:31 | 18 | let _ = namespaced_enums::B(10); - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::B;` error[E0422]: cannot find struct, variant or union type `C` in module `namespaced_enums` - --> $DIR/enums-are-namespaced-xc.rs:21:13 + --> $DIR/enums-are-namespaced-xc.rs:21:31 | 21 | let _ = namespaced_enums::C { a: 10 }; - | ^^^^^^^^^^^^^^^^^^^ not found in `namespaced_enums` + | ^ not found in `namespaced_enums` | = help: possible candidate is found in another module, you can import it into scope: `use namespaced_enums::Foo::C;` diff --git a/src/test/ui/resolve/levenshtein.stderr b/src/test/ui/resolve/levenshtein.stderr index c7c42bcf23940..4dff2620319e4 100644 --- a/src/test/ui/resolve/levenshtein.stderr +++ b/src/test/ui/resolve/levenshtein.stderr @@ -14,7 +14,7 @@ error[E0412]: cannot find type `Opiton` in this scope --> $DIR/levenshtein.rs:20:10 | 20 | type B = Opiton; // Misspelled type name from the prelude. - | ^^^^^^^^^^ did you mean `Option`? + | ^^^^^^ did you mean `Option`? error[E0412]: cannot find type `Baz` in this scope --> $DIR/levenshtein.rs:23:14 @@ -35,16 +35,16 @@ error[E0425]: cannot find function `foobar` in this scope | ^^^^^^ did you mean `foo_bar`? error[E0412]: cannot find type `first` in module `m` - --> $DIR/levenshtein.rs:32:12 + --> $DIR/levenshtein.rs:32:15 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^ did you mean `m::First`? + | ^^^^^ did you mean `First`? error[E0425]: cannot find value `second` in module `m` - --> $DIR/levenshtein.rs:32:23 + --> $DIR/levenshtein.rs:32:26 | 32 | let b: m::first = m::second; // Misspelled item in module. - | ^^^^^^^^^ did you mean `m::Second`? + | ^^^^^^ did you mean `Second`? error: aborting due to 8 previous errors diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs index 3d0c76c740ad6..68bd74719f55c 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.rs +++ b/src/test/ui/resolve/privacy-struct-ctor.rs @@ -18,7 +18,7 @@ mod m { pub struct S(u8); pub mod n { - pub(m) struct Z(pub(m::n) u8); + pub(in m) struct Z(pub(in m::n) u8); } use m::n::Z; // OK, only the type is imported diff --git a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr index 57c0ecc813505..85fb1777dea23 100644 --- a/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr +++ b/src/test/ui/resolve/suggest-path-instead-of-mod-dot-item.stderr @@ -2,55 +2,73 @@ error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5 | 27 | a.I - | ^ did you mean `a::I`? + | ^-- + | | + | did you mean `a::I`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5 | 33 | a.g() - | ^ did you mean `a::g(...)`? + | ^---- + | | + | did you mean `a::g(...)`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5 | 39 | a.b.J - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5 | 45 | a::b.J - | ^^^^ did you mean `a::b::J`? + | ^^^^-- + | | + | did you mean `a::b::J`? error[E0423]: expected value, found module `a` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5 | 51 | a.b.f(); - | ^ did you mean `a::b`? + | ^-- + | | + | did you mean `a::b`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12 | 55 | v.push(a::b); - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5 | 61 | a::b.f() - | ^^^^ did you mean `a::b::f(...)`? + | ^^^^---- + | | + | did you mean `a::b::f(...)`? error[E0423]: expected value, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5 | 67 | a::b - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error[E0423]: expected function, found module `a::b` --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5 | 73 | a::b() - | ^^^^ did you mean `a::I`? + | ^^^- + | | + | did you mean `I`? error: main function not found diff --git a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr index f0d363f7335f7..015dbfc3dc775 100644 --- a/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr +++ b/src/test/ui/resolve/unboxed-closure-sugar-nonexistent-trait.stderr @@ -2,7 +2,7 @@ error[E0405]: cannot find trait `Nonexist` in this scope --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:11:8 | 11 | fn f isize>(x: F) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0404]: expected trait, found type alias `Typedef` --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:17:8 diff --git a/src/test/ui/span/issue-40157.rs b/src/test/ui/span/issue-40157.rs new file mode 100644 index 0000000000000..8f3a7ae341736 --- /dev/null +++ b/src/test/ui/span/issue-40157.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main () { + {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} +} diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr new file mode 100644 index 0000000000000..ad1c149d2e56f --- /dev/null +++ b/src/test/ui/span/issue-40157.stderr @@ -0,0 +1,14 @@ +error: `foo` does not live long enough + --> $DIR/issue-40157.rs:12:64 + | +12 | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} + | ----------------------------------------------------------^------------- + | | | | + | | | `foo` dropped here while still borrowed + | | borrow occurs here + | borrowed value needs to live until here + | + = note: this error originates in a macro outside of the current crate + +error: aborting due to previous error + diff --git a/src/test/compile-fail/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs similarity index 100% rename from src/test/compile-fail/lint-unused-unsafe.rs rename to src/test/ui/span/lint-unused-unsafe.rs diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.stderr new file mode 100644 index 0000000000000..0df3fa43022a4 --- /dev/null +++ b/src/test/ui/span/lint-unused-unsafe.stderr @@ -0,0 +1,116 @@ +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:26:13 + | +26 | fn bad1() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: lint level defined here + --> $DIR/lint-unused-unsafe.rs:14:9 + | +14 | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:27:13 + | +27 | fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:28:20 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:28:1 + | +28 | unsafe fn bad3() { unsafe {} } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:29:13 + | +29 | fn bad4() { unsafe { callback(||{}) } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:30:20 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^ unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:30:1 + | +30 | unsafe fn bad5() { unsafe { unsf() } } //~ ERROR: unnecessary `unsafe` block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:33:9 + | +33 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +34 | | unsf() +35 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` block + --> $DIR/lint-unused-unsafe.rs:32:5 + | +32 | unsafe { // don't put the warning here + | _____^ starting here... +33 | | unsafe { //~ ERROR: unnecessary `unsafe` block +34 | | unsf() +35 | | } +36 | | } + | |_____^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:39:5 + | +39 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _____^ starting here... +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } + | |_____^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:40:9 + | +40 | unsafe { //~ ERROR: unnecessary `unsafe` block + | _________^ starting here... +41 | | unsf() +42 | | } + | |_________^ ...ending here: unnecessary `unsafe` block + | +note: because it's nested under this `unsafe` fn + --> $DIR/lint-unused-unsafe.rs:38:1 + | +38 | unsafe fn bad7() { + | _^ starting here... +39 | | unsafe { //~ ERROR: unnecessary `unsafe` block +40 | | unsafe { //~ ERROR: unnecessary `unsafe` block +41 | | unsf() +42 | | } +43 | | } +44 | | } + | |_^ ...ending here + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/span/suggestion-non-ascii.rs b/src/test/ui/span/suggestion-non-ascii.rs new file mode 100644 index 0000000000000..67dbe1dc7b566 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +fn main() { + let tup = (1,); + println!("☃{}", tup[0]); +} + diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr new file mode 100644 index 0000000000000..385c211f393c6 --- /dev/null +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -0,0 +1,11 @@ +error: cannot index a value of type `({integer},)` + --> $DIR/suggestion-non-ascii.rs:14:21 + | +14 | println!("☃{}", tup[0]); + | ^^^^^^ + | +help: to access tuple elements, use tuple indexing syntax as shown + | println!("☃{}", tup.0); + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/issue-38812-2.rs b/src/test/ui/type-check/issue-38812-2.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.rs rename to src/test/ui/type-check/issue-38812-2.rs diff --git a/src/test/ui/codemap_tests/issue-38812-2.stderr b/src/test/ui/type-check/issue-38812-2.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812-2.stderr rename to src/test/ui/type-check/issue-38812-2.stderr diff --git a/src/test/ui/codemap_tests/issue-38812.rs b/src/test/ui/type-check/issue-38812.rs similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.rs rename to src/test/ui/type-check/issue-38812.rs diff --git a/src/test/ui/codemap_tests/issue-38812.stderr b/src/test/ui/type-check/issue-38812.stderr similarity index 100% rename from src/test/ui/codemap_tests/issue-38812.stderr rename to src/test/ui/type-check/issue-38812.stderr diff --git a/src/test/ui/type-check/issue-40294.rs b/src/test/ui/type-check/issue-40294.rs new file mode 100644 index 0000000000000..d30a425d1099b --- /dev/null +++ b/src/test/ui/type-check/issue-40294.rs @@ -0,0 +1,23 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo: Sized { + fn foo(self); +} + +fn foo<'a,'b,T>(x: &'a T, y: &'b T) + where &'a T : Foo, + &'b T : Foo +{ + x.foo(); + y.foo(); +} + +fn main() { } diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr new file mode 100644 index 0000000000000..5c388c9d602ea --- /dev/null +++ b/src/test/ui/type-check/issue-40294.stderr @@ -0,0 +1,15 @@ +error[E0282]: type annotations needed + --> $DIR/issue-40294.rs:15:1 + | +15 | fn foo<'a,'b,T>(x: &'a T, y: &'b T) + | _^ starting here... +16 | | where &'a T : Foo, +17 | | &'b T : Foo +18 | | { +19 | | x.foo(); +20 | | y.foo(); +21 | | } + | |_^ ...ending here: cannot infer type for `&'a T` + +error: aborting due to previous error + diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index ceefcc9e0ec46..b9c8a84844465 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -183,15 +183,19 @@ impl Builder { let mut manifest = BTreeMap::new(); manifest.insert("manifest-version".to_string(), toml::Value::String(manifest_version)); - manifest.insert("date".to_string(), toml::Value::String(date)); + manifest.insert("date".to_string(), toml::Value::String(date.clone())); manifest.insert("pkg".to_string(), toml::encode(&pkg)); let manifest = toml::Value::Table(manifest).to_string(); let filename = format!("channel-rust-{}.toml", self.rust_release); self.write_manifest(&manifest, &filename); + let filename = format!("channel-rust-{}-date.txt", self.rust_release); + self.write_date_stamp(&date, &filename); + if self.rust_release != "beta" && self.rust_release != "nightly" { self.write_manifest(&manifest, "channel-rust-stable.toml"); + self.write_date_stamp(&date, "channel-rust-stable-date.txt"); } } @@ -218,7 +222,7 @@ impl Builder { self.package("rust-docs", &mut manifest.pkg, TARGETS); self.package("rust-src", &mut manifest.pkg, &["*"]); - if self.channel == "nightly" { + if self.rust_release == "nightly" { self.package("rust-analysis", &mut manifest.pkg, TARGETS); } @@ -271,7 +275,7 @@ impl Builder { target: target.to_string(), }); } - if self.channel == "nightly" { + if self.rust_release == "nightly" { extensions.push(Component { pkg: "rust-analysis".to_string(), target: target.to_string(), @@ -411,4 +415,11 @@ impl Builder { self.hash(&dst); self.sign(&dst); } + + fn write_date_stamp(&self, date: &str, name: &str) { + let dst = self.output.join(name); + t!(t!(File::create(&dst)).write_all(date.as_bytes())); + self.hash(&dst); + self.sign(&dst); + } } diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 1fc98a78a7c47..7530b65a9b7c4 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -5,6 +5,6 @@ version = "0.0.0" [dependencies] log = "0.3" -env_logger = { version = "0.3.5", default-features = false } +env_logger = { version = "0.4", default-features = false } rustc-serialize = "0.3" filetime = "0.1"