]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #34414 - alfiedotwtf:patch-1, r=steveklabnik
authorManish Goregaokar <manishsmail@gmail.com>
Sat, 25 Jun 2016 08:46:20 +0000 (14:16 +0530)
committerManish Goregaokar <manishsmail@gmail.com>
Sat, 25 Jun 2016 12:46:39 +0000 (18:16 +0530)
Switched tense to clarify what is happening in the example

55 files changed:
README.md
configure
mk/cfg/i686-unknown-linux-musl.mk
mk/cfg/x86_64-unknown-linux-musl.mk
mk/llvm.mk
mk/rt.mk
src/bootstrap/README.md
src/compiler-rt
src/etc/Dockerfile
src/libcollections/lib.rs
src/libcollections/str.rs
src/libcollections/vec.rs
src/libcore/fmt/mod.rs
src/libcore/slice.rs
src/libcore/str/mod.rs
src/libcore/str/pattern.rs
src/librustc/diagnostics.rs
src/librustc_resolve/diagnostics.rs
src/librustc_typeck/diagnostics.rs
src/librustdoc/html/render.rs
src/librustdoc/html/static/main.js
src/libstd/os/android/raw.rs
src/libstd/os/bitrig/raw.rs
src/libstd/os/dragonfly/raw.rs
src/libstd/os/emscripten/raw.rs
src/libstd/os/freebsd/raw.rs
src/libstd/os/ios/raw.rs
src/libstd/os/linux/raw.rs
src/libstd/os/macos/raw.rs
src/libstd/os/nacl/raw.rs
src/libstd/os/netbsd/raw.rs
src/libstd/os/openbsd/raw.rs
src/libstd/os/solaris/raw.rs
src/libstd/sync/mpsc/blocking.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mpsc/oneshot.rs
src/libstd/sync/mpsc/shared.rs
src/libstd/sync/mpsc/stream.rs
src/libstd/sync/mpsc/sync.rs
src/libstd/sys/common/wtf8.rs
src/libstd/sys/unix/ext/raw.rs
src/libstd/sys/unix/fd.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/unix/net.rs
src/libstd/sys/unix/pipe.rs
src/libstd/thread/local.rs
src/libstd/thread/mod.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/mtwt.rs
src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
src/test/run-pass-fulldeps/macro-crate.rs
src/test/run-pass/hygiene.rs [new file with mode: 0644]
src/test/run-pass/thread-local-syntax.rs [new file with mode: 0644]
src/test/rustdoc/issue-34423.rs [new file with mode: 0644]

index bc41e62b36a0094e233e6b0e8baaf23aa888e535..69bb3c5e874c0b1ced4349c124704bfedd7bb2a1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Read ["Installing Rust"] from [The Book].
    * `g++` 4.7 or later or `clang++` 3.x
    * `python` 2.7 (but not 3.x)
    * GNU `make` 3.81 or later
+   * `cmake` 2.8.8 or later
    * `curl`
    * `git`
 
index c08e8d39154dc119d42e1acf0c9c9ae192867ee1..beaac755757598e0958c877e78bed119ecee37f8 100755 (executable)
--- a/configure
+++ b/configure
@@ -775,6 +775,9 @@ probe CFG_BISON            bison
 probe CFG_GDB              gdb
 probe CFG_LLDB             lldb
 
+# For building LLVM
+probe_need CFG_CMAKE cmake
+
 # 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.
@@ -1202,9 +1205,6 @@ $ pacman -R python2 && pacman -S mingw-w64-x86_64-python2
 "
             fi
 
-            # MSVC requires cmake because that's how we're going to build LLVM
-            probe_need CFG_CMAKE cmake
-
             # There are three builds of cmake on windows: MSVC, MinGW and Cygwin
             # The Cygwin build does not have generators for Visual Studio, so
             # detect that here and error.
@@ -1477,27 +1477,16 @@ do
     elif [ -z $CFG_LLVM_ROOT ]
     then
         LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm
-        if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
-        then
-            LLVM_DBG_OPTS="--enable-debug-symbols --disable-optimized"
-            # Just use LLVM straight from its build directory to
-            # avoid 'make install' time
-            LLVM_INST_DIR=$LLVM_BUILD_DIR/Debug
-        else
-            LLVM_DBG_OPTS="--enable-optimized"
-            LLVM_INST_DIR=$LLVM_BUILD_DIR/Release
-        fi
-        if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ]
-        then
-            LLVM_ASSERTION_OPTS="--disable-assertions"
-        else
-            LLVM_ASSERTION_OPTS="--enable-assertions"
-
-            # Apparently even if we request assertions be enabled for MSVC,
-            # LLVM's CMake build system ignore this and outputs in `Release`
-            # anyway.
-            if [ ${is_msvc} -eq 0 ]; then
-                LLVM_INST_DIR=${LLVM_INST_DIR}+Asserts
+        LLVM_INST_DIR=$LLVM_BUILD_DIR
+        # For some crazy reason the MSVC output dir is different than Unix
+        if [ ${is_msvc} -ne 0 ]; then
+            if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]
+            then
+                # Just use LLVM straight from its build directory to
+                # avoid 'make install' time
+                LLVM_INST_DIR=$LLVM_BUILD_DIR/Debug
+            else
+                LLVM_INST_DIR=$LLVM_BUILD_DIR/Release
             fi
         fi
     else
@@ -1555,88 +1544,60 @@ do
                 err "can only build LLVM for x86 platforms"
                 ;;
         esac
-        CFG_CMAKE_GENERATOR=$generator
-        putvar CFG_CMAKE_GENERATOR
-    fi
-
-    if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -ne 0 ]
-    then
-        msg "configuring LLVM for $t with cmake"
-
-        CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF"
-        if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
-            CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"
-        else
-            CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release"
-        fi
-        if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ]
-        then
-            CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=OFF"
-        else
-            CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
-        fi
-
-        msg "configuring LLVM with:"
-        msg "$CMAKE_ARGS"
-
-        (cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \
-                                            -G "$CFG_CMAKE_GENERATOR" \
-                                            $CMAKE_ARGS)
-        need_ok "LLVM cmake configure failed"
+    else
+        generator="Unix Makefiles"
     fi
-
-    if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -eq 0 ]
-    then
-        # LLVM's configure doesn't recognize the new Windows triples yet
-        gnu_t=$(to_gnu_triple $t)
-
-        msg "configuring LLVM for $gnu_t"
-
-        LLVM_TARGETS="--enable-targets=x86,x86_64,arm,aarch64,mips,powerpc"
-        LLVM_BUILD="--build=$gnu_t"
-        LLVM_HOST="--host=$gnu_t"
-        LLVM_TARGET="--target=$gnu_t"
-
-        # Disable unused LLVM features
-        LLVM_OPTS="$LLVM_DBG_OPTS $LLVM_ASSERTION_OPTS --disable-docs --enable-bindings=none"
-        # Disable term-info, linkage of which comes in multiple forms,
-        # making our snapshots incompatible (#9334)
-        LLVM_OPTS="$LLVM_OPTS --disable-terminfo"
-        # Try to have LLVM pull in as few dependencies as possible (#9397)
-        LLVM_OPTS="$LLVM_OPTS --disable-zlib --disable-libffi"
-
-        # Use win32 native thread/lock apis instead of pthread wrapper.
-        # (llvm's configure tries to find pthread first, so we have to disable it explicitly.)
-        # Also note that pthreads works badly on mingw-w64 systems: #8996
-        case "$CFG_BUILD" in
-            (*-windows-gnu)
-            LLVM_OPTS="$LLVM_OPTS --disable-pthreads"
-            ;;
-        esac
-
-        case "$CFG_CC" in
-            ("ccache clang")
-            LLVM_CXX_32="ccache clang++ -Qunused-arguments"
-            LLVM_CC_32="ccache clang -Qunused-arguments"
-
-            LLVM_CXX_64="ccache clang++ -Qunused-arguments"
-            LLVM_CC_64="ccache clang -Qunused-arguments"
+    CFG_CMAKE_GENERATOR=$generator
+    putvar CFG_CMAKE_GENERATOR
+
+    msg "configuring LLVM for $t"
+
+    LLVM_CFLAGS_32=""
+    LLVM_CXXFLAGS_32=""
+    LLVM_LDFLAGS_32=""
+    LLVM_CFLAGS_64=""
+    LLVM_CXXFLAGS_64=""
+    LLVM_LDFLAGS_64=""
+
+    case "$CFG_CC" in
+        ("ccache clang")
+            LLVM_CXX_32="ccache"
+            LLVM_CC_32="ccache"
+            LLVM_CXX_32_ARG1="clang++"
+            LLVM_CC_32_ARG1="clang"
+            LLVM_CFLAGS_32="-Qunused-arguments"
+            LLVM_CXXFLAGS_32="-Qunused-arguments"
+
+            LLVM_CXX_64="ccache"
+            LLVM_CC_64="ccache"
+            LLVM_CXX_64_ARG1="clang++"
+            LLVM_CC_64_ARG1="clang"
+            LLVM_CFLAGS_64="-Qunused-arguments"
+            LLVM_CXXFLAGS_64="-Qunused-arguments"
             ;;
-            ("clang")
-            LLVM_CXX_32="clang++ -Qunused-arguments"
-            LLVM_CC_32="clang -Qunused-arguments"
-
-            LLVM_CXX_64="clang++ -Qunused-arguments"
-            LLVM_CC_64="clang -Qunused-arguments"
+        ("clang")
+            LLVM_CXX_32="clang++"
+            LLVM_CC_32="clang"
+            LLVM_CFLAGS_32="-Qunused-arguments"
+            LLVM_CXXFLAGS_32="-Qunused-arguments"
+
+            LLVM_CXX_64="clang++"
+            LLVM_CC_64="clang"
+            LLVM_CFLAGS_64="-Qunused-arguments"
+            LLVM_CXXFLAGS_64="-Qunused-arguments"
             ;;
-            ("ccache gcc")
-            LLVM_CXX_32="ccache g++"
-            LLVM_CC_32="ccache gcc"
-
-            LLVM_CXX_64="ccache g++"
-            LLVM_CC_64="ccache gcc"
+        ("ccache gcc")
+            LLVM_CXX_32="ccache"
+            LLVM_CC_32="ccache"
+            LLVM_CXX_32_ARG1="clang++"
+            LLVM_CC_32_ARG1="clang"
+
+            LLVM_CXX_64="ccache"
+            LLVM_CC_64="ccache"
+            LLVM_CXX_64_ARG1="g++"
+            LLVM_CC_64_ARG1="gcc"
             ;;
-            ("gcc")
+        ("gcc")
             LLVM_CXX_32="g++"
             LLVM_CC_32="gcc"
 
@@ -1644,7 +1605,7 @@ do
             LLVM_CC_64="gcc"
             ;;
 
-            (*)
+        (*)
             msg "inferring LLVM_CXX/CC from CXX/CC = $CXX/$CC"
             if [ -n "$CFG_ENABLE_CCACHE" ]
             then
@@ -1653,11 +1614,15 @@ do
                     err "ccache requested but not found"
                 fi
 
-                LLVM_CXX_32="ccache $CXX"
-                LLVM_CC_32="ccache $CC"
+                LLVM_CXX_32="ccache"
+                LLVM_CC_32="ccache"
+                LLVM_CXX_32_ARG1="$CXX"
+                LLVM_CC_32_ARG1="$CC"
 
-                LLVM_CXX_64="ccache $CXX"
-                LLVM_CC_64="ccache $CC"
+                LLVM_CXX_64="ccache"
+                LLVM_CC_64="ccache"
+                LLVM_CXX_64_ARG1="$CXX"
+                LLVM_CC_64_ARG1="$CC"
             else
                 LLVM_CXX_32="$CXX"
                 LLVM_CC_32="$CC"
             fi
 
             ;;
-        esac
+    esac
 
-        case "$CFG_CPUTYPE" in
-            (x86*)
-                LLVM_CXX_32="$LLVM_CXX_32 -m32"
-                LLVM_CC_32="$LLVM_CC_32 -m32"
+    case "$CFG_CPUTYPE" in
+        (x86*)
+            LLVM_CFLAGS_32="$LLVM_CFLAGS_32 -m32"
+            LLVM_CXXFLAGS_32="$LLVM_CXXFLAGS_32 -m32"
+            LLVM_LDFLAGS_32="$LLVM_LDFLAGS_32 -m32"
+            ;;
+    esac
 
-                LLVM_CFLAGS_32="-m32"
-                LLVM_CXXFLAGS_32="-m32"
-                LLVM_LDFLAGS_32="-m32"
+    if echo $t | grep -q x86_64
+    then
+        LLVM_CXX=$LLVM_CXX_64
+        LLVM_CC=$LLVM_CC_64
+        LLVM_CXX_ARG1=$LLVM_CXX_64_ARG1
+        LLVM_CC_ARG1=$LLVM_CC_64_ARG1
+        LLVM_CFLAGS=$LLVM_CFLAGS_64
+        LLVM_CXXFLAGS=$LLVM_CXXFLAGS_64
+        LLVM_LDFLAGS=$LLVM_LDFLAGS_64
+    else
+        LLVM_CXX=$LLVM_CXX_32
+        LLVM_CC=$LLVM_CC_32
+        LLVM_CXX_ARG1=$LLVM_CXX_32_ARG1
+        LLVM_CC_ARG1=$LLVM_CC_32_ARG1
+        LLVM_CFLAGS=$LLVM_CFLAGS_32
+        LLVM_CXXFLAGS=$LLVM_CXXFLAGS_32
+        LLVM_LDFLAGS=$LLVM_LDFLAGS_32
+    fi
 
-                LLVM_CFLAGS_64=""
-                LLVM_CXXFLAGS_64=""
-                LLVM_LDFLAGS_64=""
+    if [ "$CFG_USING_LIBCPP" != "0" ]; then
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_LIBCXX=ON"
+    fi
 
-                LLVM_CXX_32="$LLVM_CXX_32 -m32"
-                LLVM_CC_32="$LLVM_CC_32 -m32"
-                ;;
+    # Turn off things we don't need
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_INCLUDE_TESTS=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_INCLUDE_EXAMPLES=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_INCLUDE_DOCS=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ZLIB=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DWITH_POLY=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_TERMINFO=OFF"
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_LIBEDIT=OFF"
 
-            (*)
-                LLVM_CFLAGS_32=""
-                LLVM_CXXFLAGS_32=""
-                LLVM_LDFLAGS_32=""
+    arch="$(echo "$t" | cut -d - -f 1)"
 
-                LLVM_CFLAGS_64=""
-                LLVM_CXXFLAGS_64=""
-                LLVM_LDFLAGS_64=""
-                ;;
-        esac
+    if [ "$arch" = i686 ]; then
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_BUILD_32_BITS=ON"
+    fi
 
-        if echo $t | grep -q x86_64
-        then
-            LLVM_CXX=$LLVM_CXX_64
-            LLVM_CC=$LLVM_CC_64
-            LLVM_CFLAGS=$LLVM_CFLAGS_64
-            LLVM_CXXFLAGS=$LLVM_CXXFLAGS_64
-            LLVM_LDFLAGS=$LLVM_LDFLAGS_64
-        else
-            LLVM_CXX=$LLVM_CXX_32
-            LLVM_CC=$LLVM_CC_32
-            LLVM_CFLAGS=$LLVM_CFLAGS_32
-            LLVM_CXXFLAGS=$LLVM_CXXFLAGS_32
-            LLVM_LDFLAGS=$LLVM_LDFLAGS_32
+    if [ "$t" != "$CFG_BUILD" ]; then
+        CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CROSSCOMPILING=True"
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGET_ARCH=$arch"
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TABLEGEN=$LLVM_INST_DIR/bin/llvm-tablegen"
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_DEFAULT_TARGET_TRIPLE=$t"
+    fi
+
+    # MSVC handles compiler business itself
+    if [ ${is_msvc} -eq 0 ]; then
+        CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_COMPILER=$LLVM_CC"
+        CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_COMPILER=$LLVM_CXX"
+        CMAKE_ARGS="$CMAKE_ARGS '-DCMAKE_C_FLAGS=$LLVM_CFLAGS'"
+        CMAKE_ARGS="$CMAKE_ARGS '-DCMAKE_CXX_FLAGS=$LLVM_CXXFLAGS'"
+        if [ -n "$LLVM_CC_ARG1" ]; then
+            CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_COMPILER_ARG1=$LLVM_CC_ARG1"
         fi
+        if [ -n "$LLVM_CXX_ARG1" ]; then
+            CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_COMPILER_ARG1=$LLVM_CXX_ARG1"
+        fi
+        # FIXME: What about LDFLAGS?
+    fi
 
-        CXX=$LLVM_CXX
-        CC=$LLVM_CC
-        CFLAGS="$CFLAGS $LLVM_CFLAGS"
-        CXXFLAGS="$CXXFLAGS $LLVM_CXXFLAGS"
-        LDFLAGS="$LDFLAGS $LLVM_LDFLAGS"
+    if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
+        CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"
+    else
+        CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release"
+    fi
+    if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ]
+    then
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=OFF"
+    else
+        CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
+    fi
 
-        if [ "$CFG_USING_LIBCPP" != "0" ]; then
-            LLVM_OPTS="$LLVM_OPTS --enable-libcpp"
-        fi
+    CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC'"
+    CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
+    CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"
 
-        LLVM_FLAGS="$LLVM_TARGETS $LLVM_OPTS $LLVM_BUILD \
-                        $LLVM_HOST $LLVM_TARGET --with-python=$CFG_PYTHON"
+    if [ ${do_reconfigure} -ne 0 ]
+    then
+        msg "configuring LLVM for $t with cmake"
 
         msg "configuring LLVM with:"
-        msg "$LLVM_FLAGS"
-
-        export CXX
-        export CC
-        export CFLAGS
-        export CXXFLAGS
-        export LDFLAGS
-
-        cd $LLVM_BUILD_DIR
-        case $CFG_SRC_DIR in
-            /* | [a-z]:* | [A-Z]:*)
-                ${CFG_LLVM_SRC_DIR}configure $LLVM_FLAGS
-                ;;
-            *)
-                ${CFG_BUILD_DIR}${CFG_LLVM_SRC_DIR}configure \
-                    $LLVM_FLAGS
-                ;;
-        esac
-        need_ok "LLVM configure failed"
+        msg "$CMAKE_ARGS"
 
-        cd $CFG_BUILD_DIR
+        (cd $LLVM_BUILD_DIR && eval "$CFG_CMAKE" $CMAKE_ARGS)
+        need_ok "LLVM cmake configure failed"
     fi
 
     # Construct variables for LLVM build and install directories for
index 4c64402a73eadda8056959b571c1e2deb080464d..c1cd20a843cec5e2233296dc865acc612c309c2a 100644 (file)
@@ -1,6 +1,6 @@
 # i686-unknown-linux-musl configuration
 CC_i686-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
-CXX_i686-unknown-linux-musl=notaprogram
+CXX_i686-unknown-linux-musl=$(CXX)
 CPP_i686-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
 AR_i686-unknown-linux-musl=$(AR)
 CFG_INSTALL_ONLY_RLIB_i686-unknown-linux-musl = 1
index 62a884874bb429f78baf7371de8193e0fd99736c..dfe9de18f57878b4db44b7be3e87b75c083b757f 100644 (file)
@@ -1,6 +1,6 @@
 # x86_64-unknown-linux-musl configuration
 CC_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
-CXX_x86_64-unknown-linux-musl=notaprogram
+CXX_x86_64-unknown-linux-musl=$(CXX)
 CPP_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
 AR_x86_64-unknown-linux-musl=$(AR)
 CFG_INSTALL_ONLY_RLIB_x86_64-unknown-linux-musl = 1
index 2bdbef35badf90110721e643523465b2dd03eb5c..cc868a49e4b02201dee9b761d6672f74d9b0f5aa 100644 (file)
@@ -32,27 +32,17 @@ ifeq ($(CFG_LLVM_ROOT),)
 
 LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
 
-ifeq ($$(findstring msvc,$(1)),msvc)
-
 $$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
        @$$(call E, cmake: llvm)
+ifeq ($$(findstring msvc,$(1)),msvc)
        $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
                --config $$(LLVM_BUILD_CONFIG_MODE)
-       $$(Q)touch $$(LLVM_CONFIG_$(1))
-
-clean-llvm$(1):
-
 else
-
-$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
-       @$$(call E, make: llvm)
-       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1)) ONLY_TOOLS="$$(LLVM_TOOLS)"
+       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
+endif
        $$(Q)touch $$(LLVM_CONFIG_$(1))
 
 clean-llvm$(1):
-       $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) clean
-
-endif
 
 else
 clean-llvm$(1):
index 6591812280122067c5ec3aee46686d7f4616c070..d0ab3102d7d70d82e4979463d20664fb46d3731b 100644 (file)
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -233,35 +233,98 @@ COMPRT_DEPS := $(wildcard \
               $(S)src/compiler-rt/*/*/*/*)
 endif
 
+# compiler-rt's build system is a godawful mess. Here we figure out
+# the ridiculous platform-specific values and paths necessary to get
+# useful artifacts out of it.
+
 COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
 COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
 COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
 
-ifeq ($$(findstring msvc,$(1)),msvc)
-$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD))
-       @$$(call E, cmake: compiler-rt)
-       $$(Q)cd "$$(COMPRT_BUILD_DIR_$(1))"; $$(CFG_CMAKE) "$(S)src/compiler-rt" \
-               -DCMAKE_BUILD_TYPE=$$(LLVM_BUILD_CONFIG_MODE) \
-               -DLLVM_CONFIG_PATH=$$(LLVM_CONFIG_$$(CFG_BUILD)) \
-               -G"$$(CFG_CMAKE_GENERATOR)"
-       $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \
-               --target lib/builtins/builtins \
-               --config $$(LLVM_BUILD_CONFIG_MODE) \
-               -- //v:m //nologo
-       $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/lib/windows/$$(LLVM_BUILD_CONFIG_MODE)/clang_rt.builtins-$$(HOST_$(1)).lib $$@
+COMPRT_ARCH_$(1) := $$(word 1,$$(subst -, ,$(1)))
+
+# All this is to figure out the path to the compiler-rt bin
+ifeq ($$(findstring windows-msvc,$(1)),windows-msvc)
+COMPRT_DIR_$(1) := windows/Release
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(patsubst i%86,i386,$$(COMPRT_ARCH_$(1)))
+endif
+
+ifeq ($$(findstring windows-gnu,$(1)),windows-gnu)
+COMPRT_DIR_$(1) := windows
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1))
+endif
+
+ifeq ($$(findstring darwin,$(1)),darwin)
+COMPRT_DIR_$(1) := builtins
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins_$$(patsubst i686,i386,$$(COMPRT_ARCH_$(1)))_osx
+endif
+
+ifeq ($$(findstring ios,$(1)),ios)
+COMPRT_DIR_$(1) := builtins
+COMPRT_ARCH_$(1) := $$(patsubst armv7s,armv7em,$$(COMPRT_ARCH_$(1)))
+COMPRT_LIB_NAME_$(1) := clang_rt.hard_pic_$$(COMPRT_ARCH_$(1))_macho_embedded
+ifeq ($$(COMPRT_ARCH_$(1)),aarch64)
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins_arm64_ios
+endif
+COMPRT_DEFINES_$(1) := -DCOMPILER_RT_ENABLE_IOS=ON
+endif
+
+ifndef COMPRT_DIR_$(1)
+# NB: FreeBSD and NetBSD output to "linux"...
+COMPRT_DIR_$(1) := linux
+COMPRT_ARCH_$(1) := $$(patsubst i586,i386,$$(COMPRT_ARCH_$(1)))
+
+ifeq ($$(findstring android,$(1)),android)
+ifeq ($$(findstring arm,$$(COMPRT_ARCH_$(1))),arm)
+COMPRT_ARCH_$(1) := armhf
+endif
+endif
+
+ifeq ($$(findstring eabihf,$(1)),eabihf)
+ifeq ($$(findstring armv7,$(1)),)
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins-armhf
+endif
+endif
+
+ifndef COMPRT_LIB_NAME_$(1)
+COMPRT_LIB_NAME_$(1) := clang_rt.builtins-$$(COMPRT_ARCH_$(1))
+endif
+endif
+
+
+ifeq ($$(findstring windows-gnu,$(1)),windows-gnu)
+COMPRT_LIB_FILE_$(1) := lib$$(COMPRT_LIB_NAME_$(1)).a
+endif
+
+ifeq ($$(findstring android,$(1)),android)
+ifeq ($$(findstring arm,$(1)),arm)
+COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1))-android)
+endif
+endif
+
+ifndef COMPRT_LIB_FILE_$(1)
+COMPRT_LIB_FILE_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$$(COMPRT_LIB_NAME_$(1)))
+endif
+
+COMPRT_OUTPUT_$(1) := $$(COMPRT_BUILD_DIR_$(1))/lib/$$(COMPRT_DIR_$(1))/$$(COMPRT_LIB_FILE_$(1))
+
+ifeq ($$(findstring windows-msvc,$(1)),windows-msvc)
+COMPRT_BUILD_ARGS_$(1) := //v:m //nologo
+COMPRT_BUILD_TARGET_$(1) := lib/builtins/builtins
+COMPRT_BUILD_CC_$(1) :=
 else
-COMPRT_CC_$(1) := $$(CC_$(1))
-COMPRT_AR_$(1) := $$(AR_$(1))
-# We chomp -Werror here because GCC warns about the type signature of
-# builtins not matching its own and the build fails. It's a bit hacky,
-# but what can we do, we're building libclang-rt using GCC ......
-COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error -std=c99
-
-# FreeBSD Clang's packaging is problematic; it doesn't copy unwind.h to
-# the standard include directory. This should really be in our changes to
-# compiler-rt, but we override the CFLAGS here so there isn't much choice
-ifeq ($$(findstring freebsd,$(1)),freebsd)
-       COMPRT_CFLAGS_$(1) += -I/usr/include/c++/v1
+COMPRT_BUILD_ARGS_$(1) :=
+ifndef COMPRT_BUILD_TARGET_$(1)
+COMPRT_BUILD_TARGET_$(1) := $$(COMPRT_LIB_NAME_$(1))
+endif
+COMPRT_BUILD_CC_$(1) := -DCMAKE_C_COMPILER=$$(call FIND_COMPILER,$$(CC_$(1))) \
+                       -DCMAKE_CXX_COMPILER=$$(call FIND_COMPILER,$$(CXX_$(1)))
+
+ifeq ($$(findstring ios,$(1)),)
+COMPRT_BUILD_CC_$(1) := $$(COMPRT_BUILD_CC_$(1)) \
+                       -DCMAKE_C_FLAGS="$$(CFG_GCCISH_CFLAGS_$(1)) -Wno-error"
+endif
+
 endif
 
 ifeq ($$(findstring emscripten,$(1)),emscripten)
@@ -273,20 +336,26 @@ $$(COMPRT_LIB_$(1)):
 
 else
 
-$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
-       @$$(call E, make: compiler-rt)
-       $$(Q)$$(MAKE) -C "$(S)src/compiler-rt" \
-               ProjSrcRoot="$(S)src/compiler-rt" \
-               ProjObjRoot="$$(abspath $$(COMPRT_BUILD_DIR_$(1)))" \
-               CC='$$(COMPRT_CC_$(1))' \
-               AR='$$(COMPRT_AR_$(1))' \
-               RANLIB='$$(COMPRT_AR_$(1)) s' \
-               CFLAGS="$$(COMPRT_CFLAGS_$(1))" \
-               TargetTriple=$(1) \
-               triple-builtins
-       $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/triple/builtins/libcompiler_rt.a $$@
-
-endif # if emscripten
+$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$$(CFG_BUILD))
+       @$$(call E, cmake: compiler-rt)
+       $$(Q)rm -rf $$(COMPRT_BUILD_DIR_$(1))
+       $$(Q)mkdir $$(COMPRT_BUILD_DIR_$(1))
+       $$(Q)cd "$$(COMPRT_BUILD_DIR_$(1))"; \
+               $$(CFG_CMAKE) "$(S)src/compiler-rt" \
+               -DCMAKE_BUILD_TYPE=$$(LLVM_BUILD_CONFIG_MODE) \
+               -DLLVM_CONFIG_PATH=$$(LLVM_CONFIG_$$(CFG_BUILD)) \
+               -DCOMPILER_RT_DEFAULT_TARGET_TRIPLE=$(1) \
+               -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
+               -DCOMPILER_RT_BUILD_EMUTLS=OFF \
+               $$(COMPRT_DEFINES_$(1)) \
+               $$(COMPRT_BUILD_CC_$(1)) \
+               -G"$$(CFG_CMAKE_GENERATOR)"
+       $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \
+               --target $$(COMPRT_BUILD_TARGET_$(1)) \
+               --config $$(LLVM_BUILD_CONFIG_MODE) \
+               -- $$(COMPRT_BUILD_ARGS_$(1)) $$(MFLAGS)
+       $$(Q)cp "$$(COMPRT_OUTPUT_$(1))" $$@
+
 endif
 
 ################################################################################
@@ -310,20 +379,15 @@ ifeq ($$(findstring darwin,$$(OSTYPE_$(1))),darwin)
 $$(BACKTRACE_LIB_$(1)):
        touch $$@
 
-else
-ifeq ($$(findstring ios,$$(OSTYPE_$(1))),ios)
+else ifeq ($$(findstring ios,$$(OSTYPE_$(1))),ios)
 # See comment above
 $$(BACKTRACE_LIB_$(1)):
        touch $$@
-else
-
-ifeq ($$(findstring msvc,$(1)),msvc)
+else ifeq ($$(findstring msvc,$(1)),msvc)
 # See comment above
 $$(BACKTRACE_LIB_$(1)):
        touch $$@
-else
-
-ifeq ($$(findstring emscripten,$(1)),emscripten)
+else ifeq ($$(findstring emscripten,$(1)),emscripten)
 # FIXME: libbacktrace doesn't understand the emscripten triple
 $$(BACKTRACE_LIB_$(1)):
        touch $$@
@@ -376,10 +440,7 @@ $$(BACKTRACE_LIB_$(1)): $$(BACKTRACE_BUILD_DIR_$(1))/Makefile $$(MKFILE_DEPS)
                INCDIR=$(S)src/libbacktrace
        $$(Q)cp $$(BACKTRACE_BUILD_DIR_$(1))/.libs/libbacktrace.a $$@
 
-endif # endif for emscripten
-endif # endif for msvc
-endif # endif for ios
-endif # endif for darwin
+endif
 
 ################################################################################
 # libc/libunwind for musl
index 942f070c82fd8b8e5a928d1ef2aa0c13e98c27b2..57d644d635cf73362e0432babc5aa80887130c78 100644 (file)
@@ -50,7 +50,7 @@ compiler. What actually happens when you invoke rustbuild is:
 1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is
    responsible for downloading the stage0 compiler/Cargo binaries, and it then
    compiles the build system itself (this folder). Finally, it then invokes the
-   actual `boostrap` binary build system.
+   actual `bootstrap` binary build system.
 2. In Rust, `bootstrap` will slurp up all configuration, perform a number of
    sanity checks (compilers exist for example), and then start building the
    stage0 artifacts.
index 57315f7e07d09b6f0341ebbcd50dded6c20d782f..a1ef94b76029780a510bc2dc9c6a791bd091ff19 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 57315f7e07d09b6f0341ebbcd50dded6c20d782f
+Subproject commit a1ef94b76029780a510bc2dc9c6a791bd091ff19
index f1c56d8d3960f94519a4d111377f8fc652926258..94be84a3ebd419d8bbcb842ccd15cb1b8de91667 100644 (file)
@@ -21,7 +21,13 @@ FROM ubuntu:xenial
 RUN apt-get update && apt-get -y install \
     curl g++ gdb git make \
     libedit-dev zlib1g-dev \
-    llvm-3.7-tools
+    llvm-3.7-tools cmake
+
+# When we compile compiler-rt we pass it the llvm-config we just installed on
+# the system, but unfortunately it doesn't infer correctly where
+# LLVMConfig.cmake is so we need to coerce it a bit...
+RUN mkdir -p /usr/lib/llvm-3.7/build/share/llvm
+RUN ln -s /usr/share/llvm-3.7/cmake /usr/lib/llvm-3.7/build/share/llvm/cmake
 
 RUN mkdir /build
 WORKDIR /build
index b824817d53f1424e5cde49cc804344ab61f8e184..7ac01103d61fe8637c5f9c0046d0aaaaf4dda97e 100644 (file)
@@ -49,7 +49,6 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(step_by)]
-#![feature(str_char)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
 #![feature(unique)]
index 3364d7e16972ce316bb53000d4c769246d94faef..55308a46f0ac55c7c8645540df0cd9344d74ef67 100644 (file)
@@ -37,7 +37,7 @@
 pub use core::str::{FromStr, Utf8Error};
 #[allow(deprecated)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::str::{Lines, LinesAny, CharRange};
+pub use core::str::{Lines, LinesAny};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::str::{Split, RSplit};
 #[stable(feature = "rust1", since = "1.0.0")]
index bd1bf6e9cc37591b3269d2e1ad6308ab2fd54a48..9797113b8ad66450ac1934404e9acad9c112456a 100644 (file)
@@ -1658,7 +1658,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
     #[inline]
     fn count(self) -> usize {
-        self.size_hint().0
+        self.len()
     }
 }
 
index 6579e5dab543245ccd56934ec787974880d00adf..4ac134c2b59c8d9535d1b1d449809be809d449a4 100644 (file)
@@ -1384,7 +1384,7 @@ fn fmt(&self, f: &mut Formatter) -> Result {
         for (i, c) in self.char_indices() {
             let esc = c.escape_default();
             // If char needs escaping, flush backlog so far and write, else skip
-            if esc.size_hint() != (1, Some(1)) {
+            if esc.len() != 1 {
                 f.write_str(&self[from..i])?;
                 for c in esc {
                     f.write_char(c)?;
index 727c26ba9abd144c9910ff1f864b73dfbea3b6ae..4f11cac4eb2bec7b7e7ba6c4346e78fd5f3ed354 100644 (file)
@@ -835,7 +835,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
             #[inline]
             fn count(self) -> usize {
-                self.size_hint().0
+                self.len()
             }
 
             #[inline]
@@ -1444,7 +1444,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
     #[inline]
     fn count(self) -> usize {
-        self.size_hint().0
+        self.len()
     }
 
     #[inline]
@@ -1541,7 +1541,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
     #[inline]
     fn count(self) -> usize {
-        self.size_hint().0
+        self.len()
     }
 
     #[inline]
@@ -1632,7 +1632,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
     #[inline]
     fn count(self) -> usize {
-        self.size_hint().0
+        self.len()
     }
 
     #[inline]
index 5fc15fae5199bd344a1920248201adb721fd92ad..a32c9da9815ffc0a19d0cfdeec1138ccd6097b3d 100644 (file)
@@ -433,7 +433,7 @@ fn next(&mut self) -> Option<char> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let (len, _) = self.iter.size_hint();
+        let len = self.iter.len();
         // `(len + 3)` can't overflow, because we know that the `slice::Iter`
         // belongs to a slice in memory which has a maximum length of
         // `isize::MAX` (that's well below `usize::MAX`).
@@ -480,12 +480,12 @@ impl<'a> Iterator for CharIndices<'a> {
 
     #[inline]
     fn next(&mut self) -> Option<(usize, char)> {
-        let (pre_len, _) = self.iter.iter.size_hint();
+        let pre_len = self.iter.iter.len();
         match self.iter.next() {
             None => None,
             Some(ch) => {
                 let index = self.front_offset;
-                let (len, _) = self.iter.iter.size_hint();
+                let len = self.iter.iter.len();
                 self.front_offset += pre_len - len;
                 Some((index, ch))
             }
@@ -505,8 +505,7 @@ fn next_back(&mut self) -> Option<(usize, char)> {
         match self.iter.next_back() {
             None => None,
             Some(ch) => {
-                let (len, _) = self.iter.iter.size_hint();
-                let index = self.front_offset + len;
+                let index = self.front_offset + self.iter.iter.len();
                 Some((index, ch))
             }
         }
@@ -1292,22 +1291,6 @@ macro_rules! next { () => {{
 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
 ];
 
-/// Struct that contains a `char` and the index of the first byte of
-/// the next `char` in a string.  This can be used as a data structure
-/// for iterating over the UTF-8 bytes of a string.
-#[derive(Copy, Clone, Debug)]
-#[unstable(feature = "str_char",
-           reason = "existence of this struct is uncertain as it is frequently \
-                     able to be replaced with char.len_utf8() and/or \
-                     char/char_indices iterators",
-           issue = "27754")]
-pub struct CharRange {
-    /// Current `char`
-    pub ch: char,
-    /// Index of the first byte of the next `char`
-    pub next: usize,
-}
-
 /// Mask of the value bits of a continuation byte
 const CONT_MASK: u8 = 0b0011_1111;
 /// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte
index b803539e12b1a2fd6d91a26d56fb854851168340..53804c611e66ed52dc196b01e68eee88cce6820b 100644 (file)
@@ -310,9 +310,9 @@ fn next(&mut self) -> SearchStep {
         let s = &mut self.char_indices;
         // Compare lengths of the internal byte slice iterator
         // to find length of current char
-        let (pre_len, _) = s.iter.iter.size_hint();
+        let pre_len = s.iter.iter.len();
         if let Some((i, c)) = s.next() {
-            let (len, _) = s.iter.iter.size_hint();
+            let len = s.iter.iter.len();
             let char_len = pre_len - len;
             if self.char_eq.matches(c) {
                 return SearchStep::Match(i, i + char_len);
@@ -330,9 +330,9 @@ fn next_back(&mut self) -> SearchStep {
         let s = &mut self.char_indices;
         // Compare lengths of the internal byte slice iterator
         // to find length of current char
-        let (pre_len, _) = s.iter.iter.size_hint();
+        let pre_len = s.iter.iter.len();
         if let Some((i, c)) = s.next_back() {
-            let (len, _) = s.iter.iter.size_hint();
+            let len = s.iter.iter.len();
             let char_len = pre_len - len;
             if self.char_eq.matches(c) {
                 return SearchStep::Match(i, i + char_len);
index eb51043fcd025268a275127e36085711ba580699..538613c7fac9126ced763527e6fea95ca5f6e727 100644 (file)
@@ -298,7 +298,7 @@ trait Super<A> {
 
 Consider the following erroneous definition of a type for a list of bytes:
 
-```compile_fail
+```compile_fail,E0072
 // error, invalid recursive struct type
 struct ListNode {
     head: u8,
@@ -331,7 +331,7 @@ struct ListNode {
 You tried to give a type parameter to a type which doesn't need it. Erroneous
 code example:
 
-```compile_fail
+```compile_fail,E0109
 type X = u32<i32>; // error: type parameters are not allowed on this type
 ```
 
@@ -352,7 +352,7 @@ struct ListNode {
 You tried to give a lifetime parameter to a type which doesn't need it.
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0110
 type X = u32<'static>; // error: lifetime parameters are not allowed on
                        //        this type
 ```
@@ -370,7 +370,7 @@ struct ListNode {
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0133
 unsafe fn f() { return; } // This is the unsafe code
 
 fn main() {
@@ -410,7 +410,7 @@ fn main() {
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0137
 #![feature(main)]
 
 #[main]
@@ -437,7 +437,7 @@ fn f() {} // ok!
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0138
 #![feature(start)]
 
 #[start]
@@ -460,8 +460,7 @@ fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
 ```
 "##,
 
-// FIXME link this to the relevant turpl chapters for instilling fear of the
-//       transmute gods in the user
+// isn't thrown anymore
 E0139: r##"
 There are various restrictions on transmuting between types in Rust; for example
 types being transmuted must have the same size. To apply all these restrictions,
@@ -470,11 +469,13 @@ fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok!
 
 So, for example, the following is not allowed:
 
-```compile_fail
+```
+use std::mem::transmute;
+
 struct Foo<T>(Vec<T>);
 
 fn foo<T>(x: Vec<T>) {
-    // we are transmuting between Vec<T> and Foo<T> here
+    // we are transmuting between Vec<T> and Foo<F> here
     let y: Foo<T> = unsafe { transmute(x) };
     // do something with y
 }
@@ -542,7 +543,7 @@ fn foo<T: MyTransmutableType>(x: Vec<T>) {
 
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0152
 #![feature(lang_items)]
 
 #[lang = "panic_fmt"]
@@ -567,7 +568,7 @@ fn foo<T: MyTransmutableType>(x: Vec<T>) {
 An associated type binding was done outside of the type parameter declaration
 and `where` clause. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0229
 pub trait Foo {
     type A;
     fn boo(&self) -> <Self as Foo>::A;
@@ -604,7 +605,7 @@ fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
 
 These two examples illustrate the problem:
 
-```compile_fail
+```compile_fail,E0261
 // error, use of undeclared lifetime name `'a`
 fn foo(x: &'a str) { }
 
@@ -630,7 +631,7 @@ struct Foo<'a> {
 because the `'static` lifetime is a special built-in lifetime name denoting
 the lifetime of the entire program, this is an error:
 
-```compile_fail
+```compile_fail,E0262
 // error, invalid lifetime parameter name `'static`
 fn foo<'static>(x: &'static str) { }
 ```
@@ -640,7 +641,7 @@ fn foo<'static>(x: &'static str) { }
 A lifetime name cannot be declared more than once in the same scope. For
 example:
 
-```compile_fail
+```compile_fail,E0263
 // error, lifetime name `'a` declared twice in the same scope
 fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) { }
 ```
@@ -649,7 +650,7 @@ fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) { }
 E0264: r##"
 An unknown external lang item was used. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0264
 #![feature(lang_items)]
 
 extern "C" {
@@ -675,12 +676,9 @@ fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) { }
 Functions must eventually return a value of their return type. For example, in
 the following function:
 
-```compile_fail
-fn foo(x: u8) -> u8 {
-    if x > 0 {
-        x // alternatively, `return x`
-    }
-    // nothing here
+```compile_fail,E0269
+fn abracada_FAIL() -> String {
+    "this won't work".to_string();
 }
 ```
 
@@ -806,7 +804,7 @@ fn foo() -> ! {
 
 Here is a basic example:
 
-```compile_fail
+```compile_fail,E0271
 trait Trait { type AssociatedType; }
 
 fn foo<T>(t: T) where T: Trait<AssociatedType=u32> {
@@ -947,6 +945,8 @@ fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> {
 compiled:
 
 ```compile_fail
+#![feature(on_unimplemented)]
+
 fn foo<T: Index<u8>>(x: T){}
 
 #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
@@ -977,6 +977,8 @@ trait Index<Idx> { /* ... */ }
 compiled:
 
 ```compile_fail
+#![feature(on_unimplemented)]
+
 fn foo<T: Index<u8>>(x: T){}
 
 #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
@@ -1005,6 +1007,8 @@ trait Index<Idx> { /* ... */ }
 compiled:
 
 ```compile_fail
+#![feature(on_unimplemented)]
+
 fn foo<T: Index<u8>>(x: T){}
 
 #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
@@ -1028,7 +1032,7 @@ trait Index<Idx> { /* ... */ }
 
 For example, in the following code:
 
-```compile_fail
+```compile_fail,E0275
 trait Foo {}
 
 struct Bar<T>(T);
@@ -1048,7 +1052,7 @@ impl<T> Foo for T where Bar<T>: Foo {}
 This error occurs when a bound in an implementation of a trait does not match
 the bounds specified in the original trait. For example:
 
-```compile_fail
+```compile_fail,E0276
 trait Foo {
     fn foo<T>(x: T);
 }
@@ -1070,7 +1074,7 @@ fn foo<T>(x: T) where T: Copy {}
 You tried to use a type which doesn't implement some trait in a place which
 expected that trait. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0277
 // here we declare the Foo trait with a bar method
 trait Foo {
     fn bar(&self);
@@ -1113,7 +1117,7 @@ fn main() {
 
 Or in a generic context, an erroneous code example would look like:
 
-```compile_fail
+```compile_fail,E0277
 fn some_func<T>(foo: T) {
     println!("{:?}", foo); // error: the trait `core::fmt::Debug` is not
                            //        implemented for the type `T`
@@ -1159,7 +1163,7 @@ fn main() {
 which expected that trait. This error typically occurs when working with
 `Fn`-based types. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0281
 fn foo<F: Fn()>(x: F) { }
 
 fn main() {
@@ -1185,7 +1189,7 @@ fn main() {
 implemented by `Vec` and `String` among others. Consider the following snippet
 that reverses the characters of a string:
 
-```compile_fail
+```compile_fail,E0282
 let x = "hello".chars().rev().collect();
 ```
 
@@ -1222,7 +1226,7 @@ fn main() {
 case it is not always possible to use a type annotation, because all candidates
 have the same return type. For instance:
 
-```compile_fail
+```compile_fail,E0282
 struct Foo<T> {
     num: T,
 }
@@ -1248,7 +1252,7 @@ fn baz() {
 
 For example:
 
-```compile_fail
+```compile_fail,E0283
 trait Generator {
     fn create() -> u32;
 }
@@ -1296,10 +1300,22 @@ fn main() {
 
 E0296: r##"
 This error indicates that the given recursion limit could not be parsed. Ensure
-that the value provided is a positive integer between quotes, like so:
+that the value provided is a positive integer between quotes.
+
+Erroneous code example:
+
+```compile_fail,E0296
+#![recursion_limit]
+
+fn main() {}
+```
+
+And a working example:
 
 ```
 #![recursion_limit="1000"]
+
+fn main() {}
 ```
 "##,
 
@@ -1312,7 +1328,7 @@ fn main() {
 
 For example:
 
-```compile_fail
+```compile_fail,E0308
 let x: i32 = "I am not a number!";
 //     ~~~   ~~~~~~~~~~~~~~~~~~~~
 //      |             |
@@ -1325,7 +1341,7 @@ fn main() {
 Another situation in which this occurs is when you attempt to use the `try!`
 macro inside a function that does not return a `Result<T, E>`:
 
-```compile_fail
+```compile_fail,E0308
 use std::fs::File;
 
 fn main() {
@@ -1353,7 +1369,7 @@ fn main() {
 must be as long as the data needs to be alive, and missing the constraint that
 denotes this will cause this error.
 
-```compile_fail
+```compile_fail,E0309
 // This won't compile because T is not constrained, meaning the data
 // stored in it is not guaranteed to last as long as the reference
 struct Foo<'a, T> {
@@ -1376,7 +1392,7 @@ struct Foo<'a, T: 'a> {
 must be as long as the data needs to be alive, and missing the constraint that
 denotes this will cause this error.
 
-```compile_fail
+```compile_fail,E0310
 // This won't compile because T is not constrained to the static lifetime
 // the reference needs
 struct Foo<T> {
@@ -1430,7 +1446,7 @@ fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
 E0452: r##"
 An invalid lint attribute has been given. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0452
 #![allow(foo = "")] // error: malformed lint attribute
 ```
 
@@ -1450,7 +1466,7 @@ fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
 
 Example of erroneous code:
 
-```compile_fail
+```compile_fail,E0453
 #![forbid(non_snake_case)]
 
 #[allow(non_snake_case)]
@@ -1492,7 +1508,7 @@ fn main() {
 E0496: r##"
 A lifetime name is shadowing another lifetime name. Erroneous code example:
 
-```compile_fail
+```compile_fail,E0496
 struct Foo<'a> {
     a: &'a i32,
 }
@@ -1539,7 +1555,7 @@ fn foo() {}
 Transmute with two differently sized types was attempted. Erroneous code
 example:
 
-```compile_fail
+```compile_fail,E0512
 fn takes_u8(_: u8) {}
 
 fn main() {
@@ -1567,7 +1583,7 @@ fn main() {
 
 Examples of erroneous code:
 
-```compile_fail
+```compile_fail,E0517
 #[repr(C)]
 type Foo = u8;
 
@@ -1615,7 +1631,7 @@ impl Foo {
 
 Examples of erroneous code:
 
-```compile_fail
+```compile_fail,E0518
 #[inline(always)]
 struct Foo;
 
@@ -1642,7 +1658,7 @@ impl Foo {
 invoked (such as the handler for out-of-bounds accesses when indexing a slice).
 Erroneous code example:
 
-```compile_fail
+```compile_fail,E0522
 #![feature(lang_items)]
 
 #[lang = "cookie"]
index 208b5f11e20d125c4787cd1662898ae31d50718c..4e4f6e276d1ddfaac9e7f80e39fb4af483c7989d 100644 (file)
@@ -843,6 +843,17 @@ mod something_that_does_exist {
 let unknown_variable = 12u32;
 let x = unknown_variable; // ok!
 ```
+
+If the item is not defined in the current module, it must be imported using a
+`use` statement, like so:
+
+```ignore
+use foo::bar;
+bar();
+```
+
+If the item you are importing is not defined in some super-module of the
+current module, then it must also be declared as public (e.g., `pub fn`).
 "##,
 
 E0426: r##"
index c0cca08b6760282445e255309108c8ca33d61616..cdac66a2272379f43011c6ed51162afc3d7a5338 100644 (file)
@@ -2787,23 +2787,42 @@ fn main() {
 Erroneous code example:
 
 ```compile_fail
-trait Trait {
+trait T1 {
     type Bar;
 }
 
-type Foo = Trait<F=i32>; // error: associated type `F` not found for
-                         //        `Trait`
+type Foo = T1<F=i32>; // error: associated type `F` not found for `T1`
+
+// or:
+
+trait T2 {
+    type Bar;
+
+    // error: Baz is used but not declared
+    fn return_bool(&self, &Self::Bar, &Self::Baz) -> bool;
+}
 ```
 
-Please verify you used the right trait or you didn't misspell the
+Make sure that you have defined the associated type in the trait body.
+Also, verify that you used the right trait or you didn't misspell the
 associated type name. Example:
 
 ```
-trait Trait {
+trait T1 {
     type Bar;
 }
 
-type Foo = Trait<Bar=i32>; // ok!
+type Foo = T1<Bar=i32>; // ok!
+
+// or:
+
+trait T2 {
+    type Bar;
+    type Baz; // we declare `Baz` in our trait.
+
+    // and now we can use it here:
+    fn return_bool(&self, &Self::Bar, &Self::Baz) -> bool;
+}
 ```
 "##,
 
index 0d390a87d2050ffbb915ebd1310b57c582fbd94b..f63d37b34032ef45118a19bf0c530455f1f8f000 100644 (file)
@@ -2652,16 +2652,19 @@ fn doctraititem(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
         if !is_static || render_static {
             if !is_default_item {
                 if let Some(t) = trait_ {
-                    let it = t.items.iter().find(|i| i.name == item.name).unwrap();
-                    // We need the stability of the item from the trait because
-                    // impls can't have a stability.
-                    document_stability(w, cx, it)?;
-                    if item.doc_value().is_some() {
-                        document_full(w, item)?;
-                    } else {
-                        // In case the item isn't documented,
-                        // provide short documentation from the trait.
-                        document_short(w, it, link)?;
+                    // The trait item may have been stripped so we might not
+                    // find any documentation or stability for it.
+                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
+                        // We need the stability of the item from the trait
+                        // because impls can't have a stability.
+                        document_stability(w, cx, it)?;
+                        if item.doc_value().is_some() {
+                            document_full(w, item)?;
+                        } else {
+                            // In case the item isn't documented,
+                            // provide short documentation from the trait.
+                            document_short(w, it, link)?;
+                        }
                     }
                 } else {
                     document(w, cx, item)?;
index 14661dbaec4c5ea234f88950be37073ae4613101..68035e5abe4c28278f908ce180aca006b0c5b41b 100644 (file)
             sidebar.append(div);
         }
 
+        block("primitive", "Primitive Types");
         block("mod", "Modules");
+        block("macro", "Macros");
         block("struct", "Structs");
         block("enum", "Enums");
+        block("constant", "Constants");
+        block("static", "Statics");
         block("trait", "Traits");
         block("fn", "Functions");
-        block("macro", "Macros");
+        block("type", "Type Definitions");
     }
 
     window.initSidebarItems = initSidebarItems;
index ce6e810592c6c62e4ce71b600f382d66678c9bcc..5e473a933a67671c8374ed7b79fe8c3a72a78422 100644 (file)
@@ -20,7 +20,8 @@
 
 use os::raw::c_long;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = c_long;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
 
 #[doc(inline)]
 #[stable(feature = "raw_ext", since = "1.1.0")]
index 3fc3c5937f4da7fe9758b3179320eb355185dcf8..28958575eb229fc00529afa1a5f32195f171dc7b 100644 (file)
@@ -31,7 +31,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 83e0be0d158ec3b8747e5b99d0a7b00fcb2f2336..5da2540ceee6702bded065b32d888be984a69428 100644 (file)
@@ -30,7 +30,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 9da400a69131b58c155c87eb4e32418cc1f9743f..bcd85f8e29af9eac0491f7d18e76c70b2607bc2c 100644 (file)
@@ -25,7 +25,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = c_ulong;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
 
 #[doc(inline)]
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
index 989eef63d82cf27b38e2e276605a5898ad37f6c0..c755e5af8d94966baf771cf2ccb4b828a4683c0d 100644 (file)
@@ -30,7 +30,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 5a2de14b28b0c4be4c2eb3a138ed02aa9f8ccd45..8b34a932a170a773ec36dc7cb7ec20cf2979b314 100644 (file)
@@ -29,7 +29,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 4113966841b24bdcd0d98ef74ac0908d17b701ec..1be76961fea9efdfb9c04080ddbeb7422e306359 100644 (file)
@@ -23,7 +23,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = c_ulong;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_ulong;
 
 #[doc(inline)]
 #[stable(feature = "raw_ext", since = "1.1.0")]
index 2148670ccbd2a5ec5b580f89870df6df627a3b57..8f9b29462c4f938bc584133bd4a064774940c366 100644 (file)
@@ -29,7 +29,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 9a10fbcc30b72dac612a3f800eb58fa45e7bd359..3c3d4410a2a16bc89dc93499fb10eff32d5da164 100644 (file)
@@ -30,7 +30,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Copy, Clone)]
index bc30c1a7f48eb6c46b13f55e374bd2fc7da42c32..9b2e037e59a0bc7166779f236db1a6fcec3cb307 100644 (file)
@@ -31,7 +31,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 0e9a2128bc2a3ad84a0a82f2c665c181a45c2d98..6142f03621813b44ebb1b61206a155b1ac71016c 100644 (file)
@@ -30,7 +30,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 6a75b36bd6bdea776308356e268e9bb32fef48d1..b84fdba9ca25cdb024989fa05ffce38ada0d3935 100644 (file)
@@ -31,7 +31,8 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
 
-#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = usize;
 
 #[repr(C)]
 #[derive(Clone)]
index 0e5a98591168b5d6864a092f6a3b0a55d9ce5c6a..4a70de0e7d8fccf7bba8b7de64fc53339c1e5ef2 100644 (file)
@@ -16,6 +16,7 @@
 use marker::{Sync, Send};
 use mem;
 use clone::Clone;
+use time::Instant;
 
 struct Inner {
     thread: Thread,
@@ -74,7 +75,6 @@ pub unsafe fn cast_to_usize(self) -> usize {
     pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken {
         SignalToken { inner: mem::transmute(signal_ptr) }
     }
-
 }
 
 impl WaitToken {
@@ -83,4 +83,16 @@ pub fn wait(self) {
             thread::park()
         }
     }
+
+    /// Returns true if we wake up normally, false otherwise.
+    pub fn wait_max_until(self, end: Instant) -> bool {
+        while !self.inner.woken.load(Ordering::SeqCst) {
+            let now = Instant::now();
+            if now >= end {
+                return false;
+            }
+            thread::park_timeout(end - now)
+        }
+        true
+    }
 }
index 63b659d8db3b7b2aa85ada196f3c1cfb52b7f1f5..34bc210b3c8239eb3bfef6261653a5a35a610a82 100644 (file)
 // senders. Under the hood, however, there are actually three flavors of
 // channels in play.
 //
-// * Flavor::Oneshots - these channels are highly optimized for the one-send use case.
-//              They contain as few atomics as possible and involve one and
-//              exactly one allocation.
+// * Flavor::Oneshots - these channels are highly optimized for the one-send use
+//                      case. They contain as few atomics as possible and
+//                      involve one and exactly one allocation.
 // * Streams - these channels are optimized for the non-shared use case. They
 //             use a different concurrent queue that is more tailored for this
 //             use case. The initial allocation of this flavor of channel is not
 //
 // ## Concurrent queues
 //
-// The basic idea of Rust's Sender/Receiver types is that send() never blocks, but
-// recv() obviously blocks. This means that under the hood there must be some
-// shared and concurrent queue holding all of the actual data.
+// The basic idea of Rust's Sender/Receiver types is that send() never blocks,
+// but recv() obviously blocks. This means that under the hood there must be
+// some shared and concurrent queue holding all of the actual data.
 //
 // With two flavors of channels, two flavors of queues are also used. We have
 // chosen to use queues from a well-known author that are abbreviated as SPSC
 use mem;
 use cell::UnsafeCell;
 use marker::Reflect;
+use time::{Duration, Instant};
 
 #[unstable(feature = "mpsc_select", issue = "27800")]
 pub use self::select::{Select, Handle};
@@ -379,6 +380,19 @@ pub enum TryRecvError {
     Disconnected,
 }
 
+/// This enumeration is the list of possible errors that `recv_timeout` could
+/// not return data when called.
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[unstable(feature = "mpsc_recv_timeout", issue = "34029")]
+pub enum RecvTimeoutError {
+    /// This channel is currently empty, but the sender(s) have not yet
+    /// disconnected, so data may yet become available.
+    Timeout,
+    /// This channel's sending half has become disconnected, and there will
+    /// never be any more data received on this channel
+    Disconnected,
+}
+
 /// This enumeration is the list of the possible error outcomes for the
 /// `SyncSender::try_send` method.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -838,30 +852,30 @@ pub fn recv(&self) -> Result<T, RecvError> {
         loop {
             let new_port = match *unsafe { self.inner() } {
                 Flavor::Oneshot(ref p) => {
-                    match unsafe { (*p.get()).recv() } {
+                    match unsafe { (*p.get()).recv(None) } {
                         Ok(t) => return Ok(t),
-                        Err(oneshot::Empty) => return unreachable!(),
                         Err(oneshot::Disconnected) => return Err(RecvError),
                         Err(oneshot::Upgraded(rx)) => rx,
+                        Err(oneshot::Empty) => unreachable!(),
                     }
                 }
                 Flavor::Stream(ref p) => {
-                    match unsafe { (*p.get()).recv() } {
+                    match unsafe { (*p.get()).recv(None) } {
                         Ok(t) => return Ok(t),
-                        Err(stream::Empty) => return unreachable!(),
                         Err(stream::Disconnected) => return Err(RecvError),
                         Err(stream::Upgraded(rx)) => rx,
+                        Err(stream::Empty) => unreachable!(),
                     }
                 }
                 Flavor::Shared(ref p) => {
-                    match unsafe { (*p.get()).recv() } {
+                    match unsafe { (*p.get()).recv(None) } {
                         Ok(t) => return Ok(t),
-                        Err(shared::Empty) => return unreachable!(),
                         Err(shared::Disconnected) => return Err(RecvError),
+                        Err(shared::Empty) => unreachable!(),
                     }
                 }
                 Flavor::Sync(ref p) => return unsafe {
-                    (*p.get()).recv().map_err(|()| RecvError)
+                    (*p.get()).recv(None).map_err(|_| RecvError)
                 }
             };
             unsafe {
@@ -870,6 +884,98 @@ pub fn recv(&self) -> Result<T, RecvError> {
         }
     }
 
+    /// Attempts to wait for a value on this receiver, returning an error if the
+    /// corresponding channel has hung up, or if it waits more than `timeout`.
+    ///
+    /// This function will always block the current thread if there is no data
+    /// available and it's possible for more data to be sent. Once a message is
+    /// sent to the corresponding `Sender`, then this receiver will wake up and
+    /// return that message.
+    ///
+    /// If the corresponding `Sender` has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return `Err` to
+    /// indicate that no more messages can ever be received on this channel.
+    /// However, since channels are buffered, messages sent before the disconnect
+    /// will still be properly received.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(mpsc_recv_timeout)]
+    ///
+    /// use std::sync::mpsc::{self, RecvTimeoutError};
+    /// use std::time::Duration;
+    ///
+    /// let (send, recv) = mpsc::channel::<()>();
+    ///
+    /// let timeout = Duration::from_millis(100);
+    /// assert_eq!(Err(RecvTimeoutError::Timeout), recv.recv_timeout(timeout));
+    /// ```
+    #[unstable(feature = "mpsc_recv_timeout", issue = "34029")]
+    pub fn recv_timeout(&self, timeout: Duration) -> Result<T, RecvTimeoutError> {
+        // Do an optimistic try_recv to avoid the performance impact of
+        // Instant::now() in the full-channel case.
+        match self.try_recv() {
+            Ok(result)
+                => Ok(result),
+            Err(TryRecvError::Disconnected)
+                => Err(RecvTimeoutError::Disconnected),
+            Err(TryRecvError::Empty)
+                => self.recv_max_until(Instant::now() + timeout)
+        }
+    }
+
+    fn recv_max_until(&self, deadline: Instant) -> Result<T, RecvTimeoutError> {
+        use self::RecvTimeoutError::*;
+
+        loop {
+            let port_or_empty = match *unsafe { self.inner() } {
+                Flavor::Oneshot(ref p) => {
+                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                        Ok(t) => return Ok(t),
+                        Err(oneshot::Disconnected) => return Err(Disconnected),
+                        Err(oneshot::Upgraded(rx)) => Some(rx),
+                        Err(oneshot::Empty) => None,
+                    }
+                }
+                Flavor::Stream(ref p) => {
+                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                        Ok(t) => return Ok(t),
+                        Err(stream::Disconnected) => return Err(Disconnected),
+                        Err(stream::Upgraded(rx)) => Some(rx),
+                        Err(stream::Empty) => None,
+                    }
+                }
+                Flavor::Shared(ref p) => {
+                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                        Ok(t) => return Ok(t),
+                        Err(shared::Disconnected) => return Err(Disconnected),
+                        Err(shared::Empty) => None,
+                    }
+                }
+                Flavor::Sync(ref p) => {
+                    match unsafe { (*p.get()).recv(Some(deadline)) } {
+                        Ok(t) => return Ok(t),
+                        Err(sync::Disconnected) => return Err(Disconnected),
+                        Err(sync::Empty) => None,
+                    }
+                }
+            };
+
+            if let Some(new_port) = port_or_empty {
+                unsafe {
+                    mem::swap(self.inner_mut(), new_port.inner_mut());
+                }
+            }
+
+            // If we're already passed the deadline, and we're here without
+            // data, return a timeout, else try again.
+            if Instant::now() >= deadline {
+                return Err(Timeout);
+            }
+        }
+    }
+
     /// Returns an iterator that will block waiting for messages, but never
     /// `panic!`. It will return `None` when the channel has hung up.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1141,6 +1247,7 @@ mod tests {
     use env;
     use super::*;
     use thread;
+    use time::{Duration, Instant};
 
     pub fn stress_factor() -> usize {
         match env::var("RUST_TEST_STRESS") {
@@ -1539,6 +1646,87 @@ fn recv(rx: Receiver<Box<i32>>, i: i32) {
         }
     }
 
+    #[test]
+    fn oneshot_single_thread_recv_timeout() {
+        let (tx, rx) = channel();
+        tx.send(()).unwrap();
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+        tx.send(()).unwrap();
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    }
+
+    #[test]
+    fn stress_recv_timeout_two_threads() {
+        let (tx, rx) = channel();
+        let stress = stress_factor() + 100;
+        let timeout = Duration::from_millis(100);
+
+        thread::spawn(move || {
+            for i in 0..stress {
+                if i % 2 == 0 {
+                    thread::sleep(timeout * 2);
+                }
+                tx.send(1usize).unwrap();
+            }
+        });
+
+        let mut recv_count = 0;
+        loop {
+            match rx.recv_timeout(timeout) {
+                Ok(n) => {
+                    assert_eq!(n, 1usize);
+                    recv_count += 1;
+                }
+                Err(RecvTimeoutError::Timeout) => continue,
+                Err(RecvTimeoutError::Disconnected) => break,
+            }
+        }
+
+        assert_eq!(recv_count, stress);
+    }
+
+    #[test]
+    fn recv_timeout_upgrade() {
+        let (tx, rx) = channel::<()>();
+        let timeout = Duration::from_millis(1);
+        let _tx_clone = tx.clone();
+
+        let start = Instant::now();
+        assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout));
+        assert!(Instant::now() >= start + timeout);
+    }
+
+    #[test]
+    fn stress_recv_timeout_shared() {
+        let (tx, rx) = channel();
+        let stress = stress_factor() + 100;
+
+        for i in 0..stress {
+            let tx = tx.clone();
+            thread::spawn(move || {
+                thread::sleep(Duration::from_millis(i as u64 * 10));
+                tx.send(1usize).unwrap();
+            });
+        }
+
+        drop(tx);
+
+        let mut recv_count = 0;
+        loop {
+            match rx.recv_timeout(Duration::from_millis(10)) {
+                Ok(n) => {
+                    assert_eq!(n, 1usize);
+                    recv_count += 1;
+                }
+                Err(RecvTimeoutError::Timeout) => continue,
+                Err(RecvTimeoutError::Disconnected) => break,
+            }
+        }
+
+        assert_eq!(recv_count, stress);
+    }
+
     #[test]
     fn recv_a_lot() {
         // Regression test that we don't run out of stack in scheduler context
@@ -1547,6 +1735,24 @@ fn recv_a_lot() {
         for _ in 0..10000 { rx.recv().unwrap(); }
     }
 
+    #[test]
+    fn shared_recv_timeout() {
+        let (tx, rx) = channel();
+        let total = 5;
+        for _ in 0..total {
+            let tx = tx.clone();
+            thread::spawn(move|| {
+                tx.send(()).unwrap();
+            });
+        }
+
+        for _ in 0..total { rx.recv().unwrap(); }
+
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+        tx.send(()).unwrap();
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(()));
+    }
+
     #[test]
     fn shared_chan_stress() {
         let (tx, rx) = channel();
@@ -1689,6 +1895,7 @@ mod sync_tests {
     use env;
     use thread;
     use super::*;
+    use time::Duration;
 
     pub fn stress_factor() -> usize {
         match env::var("RUST_TEST_STRESS") {
@@ -1720,6 +1927,14 @@ fn smoke_shared() {
         assert_eq!(rx.recv().unwrap(), 1);
     }
 
+    #[test]
+    fn recv_timeout() {
+        let (tx, rx) = sync_channel::<i32>(1);
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout));
+        tx.send(1).unwrap();
+        assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
+    }
+
     #[test]
     fn smoke_threads() {
         let (tx, rx) = sync_channel::<i32>(0);
@@ -1801,6 +2016,67 @@ fn stress() {
         }
     }
 
+    #[test]
+    fn stress_recv_timeout_two_threads() {
+        let (tx, rx) = sync_channel::<i32>(0);
+
+        thread::spawn(move|| {
+            for _ in 0..10000 { tx.send(1).unwrap(); }
+        });
+
+        let mut recv_count = 0;
+        loop {
+            match rx.recv_timeout(Duration::from_millis(1)) {
+                Ok(v) => {
+                    assert_eq!(v, 1);
+                    recv_count += 1;
+                },
+                Err(RecvTimeoutError::Timeout) => continue,
+                Err(RecvTimeoutError::Disconnected) => break,
+            }
+        }
+
+        assert_eq!(recv_count, 10000);
+    }
+
+    #[test]
+    fn stress_recv_timeout_shared() {
+        const AMT: u32 = 1000;
+        const NTHREADS: u32 = 8;
+        let (tx, rx) = sync_channel::<i32>(0);
+        let (dtx, drx) = sync_channel::<()>(0);
+
+        thread::spawn(move|| {
+            let mut recv_count = 0;
+            loop {
+                match rx.recv_timeout(Duration::from_millis(10)) {
+                    Ok(v) => {
+                        assert_eq!(v, 1);
+                        recv_count += 1;
+                    },
+                    Err(RecvTimeoutError::Timeout) => continue,
+                    Err(RecvTimeoutError::Disconnected) => break,
+                }
+            }
+
+            assert_eq!(recv_count, AMT * NTHREADS);
+            assert!(rx.try_recv().is_err());
+
+            dtx.send(()).unwrap();
+        });
+
+        for _ in 0..NTHREADS {
+            let tx = tx.clone();
+            thread::spawn(move|| {
+                for _ in 0..AMT { tx.send(1).unwrap(); }
+            });
+        }
+
+        drop(tx);
+
+        drx.recv().unwrap();
+    }
+
     #[test]
     fn stress_shared() {
         const AMT: u32 = 1000;
index cb930280964b3260fbd7cb6fbc922ac3db2cb256..7a35ea6bbaaa20c184116b5f1b58be4c17090acf 100644 (file)
@@ -41,6 +41,7 @@
 use sync::mpsc::blocking::{self, SignalToken};
 use core::mem;
 use sync::atomic::{AtomicUsize, Ordering};
+use time::Instant;
 
 // Various states you can find a port in.
 const EMPTY: usize = 0;          // initial state: no data, no blocked receiver
@@ -136,7 +137,7 @@ pub fn sent(&self) -> bool {
         }
     }
 
-    pub fn recv(&mut self) -> Result<T, Failure<T>> {
+    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
         // Attempt to not block the thread (it's a little expensive). If it looks
         // like we're not empty, then immediately go through to `try_recv`.
         if self.state.load(Ordering::SeqCst) == EMPTY {
@@ -145,8 +146,16 @@ pub fn recv(&mut self) -> Result<T, Failure<T>> {
 
             // race with senders to enter the blocking state
             if self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) == EMPTY {
-                wait_token.wait();
-                debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY);
+                if let Some(deadline) = deadline {
+                    let timed_out = !wait_token.wait_max_until(deadline);
+                    // Try to reset the state
+                    if timed_out {
+                        try!(self.abort_selection().map_err(Upgraded));
+                    }
+                } else {
+                    wait_token.wait();
+                    debug_assert!(self.state.load(Ordering::SeqCst) != EMPTY);
+                }
             } else {
                 // drop the signal token, since we never blocked
                 drop(unsafe { SignalToken::cast_from_usize(ptr) });
index a3779931c7bd294291a8d75d43e487a5ca24f89b..baa4db7e5c0fa3e8e08b94395ee7c572fe4e2ac4 100644 (file)
@@ -30,6 +30,7 @@
 use sync::mpsc::select::StartResult;
 use sync::{Mutex, MutexGuard};
 use thread;
+use time::Instant;
 
 const DISCONNECTED: isize = isize::MIN;
 const FUDGE: isize = 1024;
@@ -66,7 +67,7 @@ impl<T> Packet<T> {
     // Creation of a packet *must* be followed by a call to postinit_lock
     // and later by inherit_blocker
     pub fn new() -> Packet<T> {
-        let p = Packet {
+        Packet {
             queue: mpsc::Queue::new(),
             cnt: AtomicIsize::new(0),
             steals: 0,
@@ -75,8 +76,7 @@ pub fn new() -> Packet<T> {
             port_dropped: AtomicBool::new(false),
             sender_drain: AtomicIsize::new(0),
             select_lock: Mutex::new(()),
-        };
-        return p;
+        }
     }
 
     // This function should be used after newly created Packet
@@ -216,7 +216,7 @@ pub fn send(&mut self, t: T) -> Result<(), T> {
         Ok(())
     }
 
-    pub fn recv(&mut self) -> Result<T, Failure> {
+    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure> {
         // This code is essentially the exact same as that found in the stream
         // case (see stream.rs)
         match self.try_recv() {
@@ -226,7 +226,14 @@ pub fn recv(&mut self) -> Result<T, Failure> {
 
         let (wait_token, signal_token) = blocking::tokens();
         if self.decrement(signal_token) == Installed {
-            wait_token.wait()
+            if let Some(deadline) = deadline {
+                let timed_out = !wait_token.wait_max_until(deadline);
+                if timed_out {
+                    self.abort_selection(false);
+                }
+            } else {
+                wait_token.wait();
+            }
         }
 
         match self.try_recv() {
index e8012ca470b02190c03a9b96766e1591cf5424c4..aa1254c8641f571aef2f68c16a9be534e97707f8 100644 (file)
@@ -25,6 +25,7 @@
 use core::cmp;
 use core::isize;
 use thread;
+use time::Instant;
 
 use sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool};
 use sync::mpsc::Receiver;
@@ -172,7 +173,7 @@ fn decrement(&mut self, token: SignalToken) -> Result<(), SignalToken> {
         Err(unsafe { SignalToken::cast_from_usize(ptr) })
     }
 
-    pub fn recv(&mut self) -> Result<T, Failure<T>> {
+    pub fn recv(&mut self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
         // Optimistic preflight check (scheduling is expensive).
         match self.try_recv() {
             Err(Empty) => {}
@@ -183,7 +184,15 @@ pub fn recv(&mut self) -> Result<T, Failure<T>> {
         // initiate the blocking protocol.
         let (wait_token, signal_token) = blocking::tokens();
         if self.decrement(signal_token).is_ok() {
-            wait_token.wait()
+            if let Some(deadline) = deadline {
+                let timed_out = !wait_token.wait_max_until(deadline);
+                if timed_out {
+                    try!(self.abort_selection(/* was_upgrade = */ false)
+                             .map_err(Upgraded));
+                }
+            } else {
+                wait_token.wait();
+            }
         }
 
         match self.try_recv() {
@@ -332,7 +341,7 @@ pub fn can_recv(&mut self) -> Result<bool, Receiver<T>> {
         // the internal state.
         match self.queue.peek() {
             Some(&mut GoUp(..)) => {
-                match self.recv() {
+                match self.recv(None) {
                     Err(Upgraded(port)) => Err(port),
                     _ => unreachable!(),
                 }
index b98fc2859afcc43a09e189ac3ca3b9af53271507..f021689acad58849a9bc986d5435e3ee06d0eb0b 100644 (file)
@@ -44,6 +44,7 @@
 use sync::mpsc::blocking::{self, WaitToken, SignalToken};
 use sync::mpsc::select::StartResult::{self, Installed, Abort};
 use sync::{Mutex, MutexGuard};
+use time::Instant;
 
 pub struct Packet<T> {
     /// Only field outside of the mutex. Just done for kicks, but mainly because
@@ -126,6 +127,38 @@ fn wait<'a, 'b, T>(lock: &'a Mutex<State<T>>,
     lock.lock().unwrap() // relock
 }
 
+/// Same as wait, but waiting at most until `deadline`.
+fn wait_timeout_receiver<'a, 'b, T>(lock: &'a Mutex<State<T>>,
+                                    deadline: Instant,
+                                    mut guard: MutexGuard<'b, State<T>>,
+                                    success: &mut bool)
+                                    -> MutexGuard<'a, State<T>>
+{
+    let (wait_token, signal_token) = blocking::tokens();
+    match mem::replace(&mut guard.blocker, BlockedReceiver(signal_token)) {
+        NoneBlocked => {}
+        _ => unreachable!(),
+    }
+    drop(guard);         // unlock
+    *success = wait_token.wait_max_until(deadline);   // block
+    let mut new_guard = lock.lock().unwrap(); // relock
+    if !*success {
+        abort_selection(&mut new_guard);
+    }
+    new_guard
+}
+
+fn abort_selection<'a, T>(guard: &mut MutexGuard<'a , State<T>>) -> bool {
+    match mem::replace(&mut guard.blocker, NoneBlocked) {
+        NoneBlocked => true,
+        BlockedSender(token) => {
+            guard.blocker = BlockedSender(token);
+            true
+        }
+        BlockedReceiver(token) => { drop(token); false }
+    }
+}
+
 /// Wakes up a thread, dropping the lock at the correct time
 fn wakeup<T>(token: SignalToken, guard: MutexGuard<State<T>>) {
     // We need to be careful to wake up the waiting thread *outside* of the mutex
@@ -238,22 +271,37 @@ pub fn try_send(&self, t: T) -> Result<(), super::TrySendError<T>> {
     //
     // When reading this, remember that there can only ever be one receiver at
     // time.
-    pub fn recv(&self) -> Result<T, ()> {
+    pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure> {
         let mut guard = self.lock.lock().unwrap();
 
-        // Wait for the buffer to have something in it. No need for a while loop
-        // because we're the only receiver.
-        let mut waited = false;
+        let mut woke_up_after_waiting = false;
+        // Wait for the buffer to have something in it. No need for a
+        // while loop because we're the only receiver.
         if !guard.disconnected && guard.buf.size() == 0 {
-            guard = wait(&self.lock, guard, BlockedReceiver);
-            waited = true;
+            if let Some(deadline) = deadline {
+                guard = wait_timeout_receiver(&self.lock,
+                                              deadline,
+                                              guard,
+                                              &mut woke_up_after_waiting);
+            } else {
+                guard = wait(&self.lock, guard, BlockedReceiver);
+                woke_up_after_waiting = true;
+            }
+        }
+
+        // NB: Channel could be disconnected while waiting, so the order of
+        // these conditionals is important.
+        if guard.disconnected && guard.buf.size() == 0 {
+            return Err(Disconnected);
         }
-        if guard.disconnected && guard.buf.size() == 0 { return Err(()) }
 
         // Pick up the data, wake up our neighbors, and carry on
-        assert!(guard.buf.size() > 0);
+        assert!(guard.buf.size() > 0 || (deadline.is_some() && !woke_up_after_waiting));
+
+        if guard.buf.size() == 0 { return Err(Empty); }
+
         let ret = guard.buf.dequeue();
-        self.wakeup_senders(waited, guard);
+        self.wakeup_senders(woke_up_after_waiting, guard);
         Ok(ret)
     }
 
@@ -392,14 +440,7 @@ pub fn start_selection(&self, token: SignalToken) -> StartResult {
     // The return value indicates whether there's data on this port.
     pub fn abort_selection(&self) -> bool {
         let mut guard = self.lock.lock().unwrap();
-        match mem::replace(&mut guard.blocker, NoneBlocked) {
-            NoneBlocked => true,
-            BlockedSender(token) => {
-                guard.blocker = BlockedSender(token);
-                true
-            }
-            BlockedReceiver(token) => { drop(token); false }
-        }
+        abort_selection(&mut guard)
     }
 }
 
index d705b8986d0b1108d23985c1820004aa36ed9296..b6be85a4dfa2879b04548c74964195a5f3f8c1ce 100644 (file)
@@ -715,7 +715,7 @@ fn next(&mut self) -> Option<CodePoint> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let (len, _) = self.bytes.size_hint();
+        let len = self.bytes.len();
         (len.saturating_add(3) / 4, Some(len))
     }
 }
index 96535e886041803b50598d8e4a1f1f2ae1811800..7972990e67dfeb2760840c0affb98ff60ffa42e8 100644 (file)
@@ -23,7 +23,7 @@
 #[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
 
 #[doc(inline)]
-#[unstable(feature = "pthread_t", issue = "29791")]
+#[stable(feature = "pthread_t", since = "1.8.0")]
 pub use sys::platform::raw::pthread_t;
 #[doc(inline)]
 #[stable(feature = "raw_ext", since = "1.1.0")]
index 94c48be02ffc4b3f3093763b8e8b557100bf6499..b99f4a2eacde563d489fa690b06bbb19fea50f35 100644 (file)
@@ -62,32 +62,31 @@ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
     }
 
     #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))]
-    pub fn set_cloexec(&self) {
+    pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
-            let ret = libc::ioctl(self.fd, libc::FIOCLEX);
-            debug_assert_eq!(ret, 0);
+            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
+            Ok(())
         }
     }
     #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
-    pub fn set_cloexec(&self) {
+    pub fn set_cloexec(&self) -> io::Result<()> {
         unsafe {
-            let previous = libc::fcntl(self.fd, libc::F_GETFD);
-            let ret = libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC);
-            debug_assert_eq!(ret, 0);
+            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+            cvt(libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC))?;
+            Ok(())
         }
     }
 
-    pub fn set_nonblocking(&self, nonblocking: bool) {
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         unsafe {
-            let previous = libc::fcntl(self.fd, libc::F_GETFL);
-            debug_assert!(previous != -1);
+            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
             let new = if nonblocking {
                 previous | libc::O_NONBLOCK
             } else {
                 previous & !libc::O_NONBLOCK
             };
-            let ret = libc::fcntl(self.fd, libc::F_SETFL, new);
-            debug_assert!(ret != -1);
+            cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
+            Ok(())
         }
     }
 
@@ -114,8 +113,8 @@ pub fn duplicate(&self) -> io::Result<FileDesc> {
 
         let make_filedesc = |fd| {
             let fd = FileDesc::new(fd);
-            fd.set_cloexec();
-            fd
+            fd.set_cloexec()?;
+            Ok(fd)
         };
         static TRY_CLOEXEC: AtomicBool =
             AtomicBool::new(!cfg!(target_os = "android"));
@@ -127,7 +126,7 @@ pub fn duplicate(&self) -> io::Result<FileDesc> {
                 // though it reported doing so on F_DUPFD_CLOEXEC.
                 Ok(fd) => {
                     return Ok(if cfg!(target_os = "linux") {
-                        make_filedesc(fd)
+                        make_filedesc(fd)?
                     } else {
                         FileDesc::new(fd)
                     })
@@ -138,7 +137,7 @@ pub fn duplicate(&self) -> io::Result<FileDesc> {
                 Err(e) => return Err(e),
             }
         }
-        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).map(make_filedesc)
+        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
     }
 }
 
index 7f23ae53fcd1ac7375e0f3abe140b6d9f38f6724..0524851df91abeb0c091a0a254b616388dd4b007 100644 (file)
@@ -418,7 +418,7 @@ pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
         // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc
         // that we support, so we only do this on Linux currently.
         if cfg!(target_os = "linux") {
-            fd.set_cloexec();
+            fd.set_cloexec()?;
         }
 
         Ok(File(fd))
index 830957a7e59c76943a6f080b28e98473e008b856..a784741c88cc7f3536857065b6490db772e82dc1 100644 (file)
@@ -77,7 +77,7 @@ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
 
             let fd = cvt(libc::socket(fam, ty, 0))?;
             let fd = FileDesc::new(fd);
-            fd.set_cloexec();
+            fd.set_cloexec()?;
             Ok(Socket(fd))
         }
     }
@@ -99,9 +99,9 @@ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
 
             cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
             let a = FileDesc::new(fds[0]);
-            a.set_cloexec();
             let b = FileDesc::new(fds[1]);
-            b.set_cloexec();
+            a.set_cloexec()?;
+            b.set_cloexec()?;
             Ok((Socket(a), Socket(b)))
         }
     }
@@ -132,7 +132,7 @@ fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
             libc::accept(self.0.raw(), storage, len)
         })?;
         let fd = FileDesc::new(fd);
-        fd.set_cloexec();
+        fd.set_cloexec()?;
         Ok(Socket(fd))
     }
 
index beca2d467536d82a4ea9acf2956b9df7055b3737..2dde9c0e615f2ec055540adea76fc09ecae55d7b 100644 (file)
@@ -44,17 +44,18 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
         }
     }
     if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } {
-        Ok((AnonPipe::from_fd(fds[0]), AnonPipe::from_fd(fds[1])))
+        let fd0 = FileDesc::new(fds[0]);
+        let fd1 = FileDesc::new(fds[1]);
+        Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?))
     } else {
         Err(io::Error::last_os_error())
     }
 }
 
 impl AnonPipe {
-    pub fn from_fd(fd: libc::c_int) -> AnonPipe {
-        let fd = FileDesc::new(fd);
-        fd.set_cloexec();
-        AnonPipe(fd)
+    pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
+        fd.set_cloexec()?;
+        Ok(AnonPipe(fd))
     }
 
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
@@ -81,8 +82,8 @@ pub fn read2(p1: AnonPipe,
     // in the `select` loop below, and we wouldn't want one to block the other!
     let p1 = p1.into_fd();
     let p2 = p2.into_fd();
-    p1.set_nonblocking(true);
-    p2.set_nonblocking(true);
+    p1.set_nonblocking(true)?;
+    p2.set_nonblocking(true)?;
 
     let max = cmp::max(p1.raw(), p2.raw());
     loop {
@@ -114,11 +115,11 @@ pub fn read2(p1: AnonPipe,
             }
         };
         if read(&p1, v1)? {
-            p2.set_nonblocking(false);
+            p2.set_nonblocking(false)?;
             return p2.read_to_end(v2).map(|_| ());
         }
         if read(&p2, v2)? {
-            p1.set_nonblocking(false);
+            p1.set_nonblocking(false)?;
             return p1.read_to_end(v1).map(|_| ());
         }
     }
index 6b54ec8afca9cfff881dffc814082ded0b41e62d..152b9771086b80c7a32017eab810b14a0a152a96 100644 (file)
@@ -100,18 +100,52 @@ pub struct LocalKey<T: 'static> {
 
 /// Declare a new thread local storage key of type `std::thread::LocalKey`.
 ///
+/// # Syntax
+///
+/// The macro wraps any number of static declarations and makes them thread local.
+/// Each static may be public or private, and attributes are allowed. Example:
+///
+/// ```
+/// use std::cell::RefCell;
+/// thread_local! {
+///     pub static FOO: RefCell<u32> = RefCell::new(1);
+///
+///     #[allow(unused)]
+///     static BAR: RefCell<f32> = RefCell::new(1.0);
+/// }
+/// # fn main() {}
+/// ```
+///
 /// See [LocalKey documentation](thread/struct.LocalKey.html) for more
 /// information.
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow_internal_unstable]
 macro_rules! thread_local {
-    (static $name:ident: $t:ty = $init:expr) => (
-        static $name: $crate::thread::LocalKey<$t> =
+    // rule 0: empty (base case for the recursion)
+    () => {};
+
+    // rule 1: process multiple declarations where the first one is private
+    ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
+        thread_local!($(#[$attr])* static $name: $t = $init); // go to rule 2
+        thread_local!($($rest)*);
+    );
+
+    // rule 2: handle a single private declaration
+    ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => (
+        $(#[$attr])* static $name: $crate::thread::LocalKey<$t> =
             __thread_local_inner!($t, $init);
     );
-    (pub static $name:ident: $t:ty = $init:expr) => (
-        pub static $name: $crate::thread::LocalKey<$t> =
+
+    // rule 3: handle multiple declarations where the first one is public
+    ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
+        thread_local!($(#[$attr])* pub static $name: $t = $init); // go to rule 4
+        thread_local!($($rest)*);
+    );
+
+    // rule 4: handle a single public declaration
+    ($(#[$attr:meta])* pub static $name:ident: $t:ty = $init:expr) => (
+        $(#[$attr])* pub static $name: $crate::thread::LocalKey<$t> =
             __thread_local_inner!($t, $init);
     );
 }
index 1f78b32bcf38e9c8f7445d3e895a23d4080f1f85..d83d45518e4044e41d66d53886f986e6808ed905 100644 (file)
@@ -482,9 +482,9 @@ pub struct Thread {
 impl Thread {
     // Used only internally to construct a thread object without spawning
     fn new(name: Option<String>) -> Thread {
-        let cname = name.map(|n| CString::new(n).unwrap_or_else(|_| {
-            panic!("thread name may not contain interior null bytes")
-        }));
+        let cname = name.map(|n| {
+            CString::new(n).expect("thread name may not contain interior null bytes")
+        });
         Thread {
             inner: Arc::new(Inner {
                 name: cname,
index 5da81a269ab8b17473a66bbbce9988527d11cb04..f2a005573d561bd6d1c3fdc028173cdbbe2dd54e 100644 (file)
@@ -12,6 +12,7 @@
 
 use ast;
 use ast::{Name, PatKind};
+use attr::HasAttrs;
 use codemap;
 use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
 use errors::DiagnosticBuilder;
@@ -40,29 +41,31 @@ pub enum Annotatable {
     ImplItem(P<ast::ImplItem>),
 }
 
-impl Annotatable {
-    pub fn attrs(&self) -> &[ast::Attribute] {
+impl HasAttrs for Annotatable {
+    fn attrs(&self) -> &[ast::Attribute] {
         match *self {
-            Annotatable::Item(ref i) => &i.attrs,
-            Annotatable::TraitItem(ref ti) => &ti.attrs,
-            Annotatable::ImplItem(ref ii) => &ii.attrs,
+            Annotatable::Item(ref item) => &item.attrs,
+            Annotatable::TraitItem(ref trait_item) => &trait_item.attrs,
+            Annotatable::ImplItem(ref impl_item) => &impl_item.attrs,
         }
     }
 
-    pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
+    fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self {
         match self {
-            Annotatable::Item(i) => Annotatable::Item(i.map(|i| ast::Item {
-                attrs: attrs,
-                ..i
-            })),
-            Annotatable::TraitItem(i) => Annotatable::TraitItem(i.map(|ti| {
-                ast::TraitItem { attrs: attrs, ..ti }
-            })),
-            Annotatable::ImplItem(i) => Annotatable::ImplItem(i.map(|ii| {
-                ast::ImplItem { attrs: attrs, ..ii }
-            })),
+            Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)),
+            Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)),
+            Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)),
         }
     }
+}
+
+impl Annotatable {
+    pub fn attrs(&self) -> &[ast::Attribute] {
+        HasAttrs::attrs(self)
+    }
+    pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable {
+        self.map_attrs(|_| attrs)
+    }
 
     pub fn expect_item(self) -> P<ast::Item> {
         match self {
@@ -129,9 +132,7 @@ fn expand(&self,
     }
 }
 
-// A more flexible ItemKind::Modifier (ItemKind::Modifier should go away, eventually, FIXME).
-// meta_item is the annotation, item is the item being modified, parent_item
-// is the impl or trait item is declared in if item is part of such a thing.
+// `meta_item` is the annotation, and `item` is the item being modified.
 // FIXME Decorators should follow the same pattern too.
 pub trait MultiItemModifier {
     fn expand(&self,
@@ -139,22 +140,26 @@ fn expand(&self,
               span: Span,
               meta_item: &ast::MetaItem,
               item: Annotatable)
-              -> Annotatable;
+              -> Vec<Annotatable>;
 }
 
-impl<F> MultiItemModifier for F
-    where F: Fn(&mut ExtCtxt,
-                Span,
-                &ast::MetaItem,
-                Annotatable) -> Annotatable
+impl<F, T> MultiItemModifier for F
+    where F: Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable) -> T,
+          T: Into<Vec<Annotatable>>,
 {
     fn expand(&self,
               ecx: &mut ExtCtxt,
               span: Span,
               meta_item: &ast::MetaItem,
               item: Annotatable)
-              -> Annotatable {
-        (*self)(ecx, span, meta_item, item)
+              -> Vec<Annotatable> {
+        (*self)(ecx, span, meta_item, item).into()
+    }
+}
+
+impl Into<Vec<Annotatable>> for Annotatable {
+    fn into(self) -> Vec<Annotatable> {
+        vec![self]
     }
 }
 
index d63411568dce80acd3a2ffd7e605fb5ca12f3e0c..5beb49372077e83bc22e3bf71f2a87830a507380 100644 (file)
@@ -13,6 +13,7 @@
 use ast::{MacStmtStyle, Mrk, Stmt, StmtKind, ItemKind};
 use ast::TokenTree;
 use ast;
+use attr::HasAttrs;
 use ext::mtwt;
 use ext::build::AstBuilder;
 use attr;
@@ -681,7 +682,7 @@ pub struct IdentRenamer<'a> {
 
 impl<'a> Folder for IdentRenamer<'a> {
     fn fold_ident(&mut self, id: Ident) -> Ident {
-        Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt))
+        mtwt::apply_renames(self.renames, id)
     }
     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
         fold::noop_fold_mac(mac, self)
@@ -705,8 +706,7 @@ fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
 
         pat.map(|ast::Pat {id, node, span}| match node {
             PatKind::Ident(binding_mode, Spanned{span: sp, node: ident}, sub) => {
-                let new_ident = Ident::new(ident.name,
-                                           mtwt::apply_renames(self.renames, ident.ctxt));
+                let new_ident = mtwt::apply_renames(self.renames, ident);
                 let new_node =
                     PatKind::Ident(binding_mode,
                                   Spanned{span: sp, node: new_ident},
@@ -725,11 +725,7 @@ fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
     }
 }
 
-fn expand_annotatable(a: Annotatable,
-                      fld: &mut MacroExpander)
-                      -> SmallVector<Annotatable> {
-    let a = expand_item_multi_modifier(a, fld);
-
+fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
     let new_items: SmallVector<Annotatable> = match a {
         Annotatable::Item(it) => match it.node {
             ast::ItemKind::Mac(..) => {
@@ -797,29 +793,6 @@ fn decorate(a: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable>
     new_items
 }
 
-// Partition a set of attributes into one kind of attribute, and other kinds.
-macro_rules! partition {
-    ($fn_name: ident, $variant: ident) => {
-        #[allow(deprecated)] // The `allow` is needed because the `Modifier` variant might be used.
-        fn $fn_name(attrs: &[ast::Attribute],
-                    fld: &MacroExpander)
-                     -> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
-            attrs.iter().cloned().partition(|attr| {
-                match fld.cx.syntax_env.find(intern(&attr.name())) {
-                    Some(rc) => match *rc {
-                        $variant(..) => true,
-                        _ => false
-                    },
-                    _ => false
-                }
-            })
-        }
-    }
-}
-
-partition!(multi_modifiers, MultiModifier);
-
-
 fn expand_decorators(a: Annotatable,
                      fld: &mut MacroExpander,
                      decorator_items: &mut SmallVector<Annotatable>,
@@ -865,46 +838,41 @@ fn expand_decorators(a: Annotatable,
     }
 }
 
-fn expand_item_multi_modifier(mut it: Annotatable,
-                              fld: &mut MacroExpander)
-                              -> Annotatable {
-    let (modifiers, other_attrs) = multi_modifiers(it.attrs(), fld);
-
-    // Update the attrs, leave everything else alone. Is this mutation really a good idea?
-    it = it.fold_attrs(other_attrs);
-
-    if modifiers.is_empty() {
-        return it
-    }
-
-    for attr in &modifiers {
-        let mname = intern(&attr.name());
-
-        match fld.cx.syntax_env.find(mname) {
-            Some(rc) => match *rc {
-                MultiModifier(ref mac) => {
-                    attr::mark_used(attr);
-                    fld.cx.bt_push(ExpnInfo {
-                        call_site: attr.span,
-                        callee: NameAndSpan {
-                            format: MacroAttribute(mname),
-                            span: Some(attr.span),
-                            // attributes can do whatever they like,
-                            // for now
-                            allow_internal_unstable: true,
-                        }
-                    });
-                    it = mac.expand(fld.cx, attr.span, &attr.node.value, it);
-                    fld.cx.bt_pop();
+fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVector<Annotatable> {
+    let mut multi_modifier = None;
+    item = item.map_attrs(|mut attrs| {
+        for i in 0..attrs.len() {
+            if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
+                if let MultiModifier(..) = *extension {
+                    multi_modifier = Some((attrs.remove(i), extension));
+                    break;
                 }
-                _ => unreachable!()
-            },
-            _ => unreachable!()
+            }
         }
-    }
+        attrs
+    });
 
-    // Expansion may have added new ItemKind::Modifiers.
-    expand_item_multi_modifier(it, fld)
+    match multi_modifier {
+        None => expand_multi_modified(item, fld),
+        Some((attr, extension)) => match *extension {
+            MultiModifier(ref mac) => {
+                attr::mark_used(&attr);
+                fld.cx.bt_push(ExpnInfo {
+                    call_site: attr.span,
+                    callee: NameAndSpan {
+                        format: MacroAttribute(intern(&attr.name())),
+                        span: Some(attr.span),
+                        // attributes can do whatever they like, for now
+                        allow_internal_unstable: true,
+                    }
+                });
+                let modified = mac.expand(fld.cx, attr.span, &attr.node.value, item);
+                fld.cx.bt_pop();
+                modified.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
+            }
+            _ => unreachable!(),
+        }
+    }
 }
 
 fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
@@ -1266,7 +1234,7 @@ mod tests {
     use ext::mtwt;
     use fold::Folder;
     use parse;
-    use parse::token::{self, keywords};
+    use parse::token;
     use util::parser_testing::{string_to_parser};
     use util::parser_testing::{string_to_pat, string_to_crate, strs_to_idents};
     use visit;
@@ -1396,267 +1364,10 @@ fn crate_bindings(the_crate : &ast::Crate) -> Vec<ast::Ident> {
             );
     }
 
-    // renaming tests expand a crate and then check that the bindings match
-    // the right varrefs. The specification of the test case includes the
-    // text of the crate, and also an array of arrays.  Each element in the
-    // outer array corresponds to a binding in the traversal of the AST
-    // induced by visit.  Each of these arrays contains a list of indexes,
-    // interpreted as the varrefs in the varref traversal that this binding
-    // should match.  So, for instance, in a program with two bindings and
-    // three varrefs, the array [[1, 2], [0]] would indicate that the first
-    // binding should match the second two varrefs, and the second binding
-    // should match the first varref.
-    //
-    // Put differently; this is a sparse representation of a boolean matrix
-    // indicating which bindings capture which identifiers.
-    //
-    // Note also that this matrix is dependent on the implicit ordering of
-    // the bindings and the varrefs discovered by the name-finder and the path-finder.
-    //
-    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
-    // names; differences in marks don't matter any more.
-    //
-    // oog... I also want tests that check "bound-identifier-=?". That is,
-    // not just "do these have the same name", but "do they have the same
-    // name *and* the same marks"? Understanding this is really pretty painful.
-    // in principle, you might want to control this boolean on a per-varref basis,
-    // but that would make things even harder to understand, and might not be
-    // necessary for thorough testing.
-    type RenamingTest = (&'static str, Vec<Vec<usize>>, bool);
-
-    #[test]
-    fn automatic_renaming () {
-        let tests: Vec<RenamingTest> =
-            vec!(// b & c should get new names throughout, in the expr too:
-                ("fn a() -> i32 { let b = 13; let c = b; b+c }",
-                 vec!(vec!(0,1),vec!(2)), false),
-                // both x's should be renamed (how is this causing a bug?)
-                ("fn main () {let x: i32 = 13;x;}",
-                 vec!(vec!(0)), false),
-                // the use of b after the + should be renamed, the other one not:
-                ("macro_rules! f (($x:ident) => (b + $x)); fn a() -> i32 { let b = 13; f!(b)}",
-                 vec!(vec!(1)), false),
-                // the b before the plus should not be renamed (requires marks)
-                ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})); fn a() -> i32 { f!(b)}",
-                 vec!(vec!(1)), false),
-                // the marks going in and out of letty should cancel, allowing that $x to
-                // capture the one following the semicolon.
-                // this was an awesome test case, and caught a *lot* of bugs.
-                ("macro_rules! letty(($x:ident) => (let $x = 15;));
-                  macro_rules! user(($x:ident) => ({letty!($x); $x}));
-                  fn main() -> i32 {user!(z)}",
-                 vec!(vec!(0)), false)
-                );
-        for (idx,s) in tests.iter().enumerate() {
-            run_renaming_test(s,idx);
-        }
-    }
-
-    // no longer a fixme #8062: this test exposes a *potential* bug; our system does
-    // not behave exactly like MTWT, but a conversation with Matthew Flatt
-    // suggests that this can only occur in the presence of local-expand, which
-    // we have no plans to support. ... unless it's needed for item hygiene....
-    #[ignore]
-    #[test]
-    fn issue_8062(){
-        run_renaming_test(
-            &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}",
-              vec!(vec!(0)), true), 0)
-    }
-
-    // FIXME #6994:
-    // the z flows into and out of two macros (g & f) along one path, and one
-    // (just g) along the other, so the result of the whole thing should
-    // be "let z_123 = 3; z_123"
-    #[ignore]
-    #[test]
-    fn issue_6994(){
-        run_renaming_test(
-            &("macro_rules! g (($x:ident) =>
-              ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}));
-              fn a(){g!(z)}",
-              vec!(vec!(0)),false),
-            0)
-    }
-
-    // match variable hygiene. Should expand into
-    // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}}
-    #[test]
-    fn issue_9384(){
-        run_renaming_test(
-            &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}}));
-              fn z() {match 8 {x => bad_macro!(x)}}",
-              // NB: the third "binding" is the repeat of the second one.
-              vec!(vec!(1,3),vec!(0,2),vec!(0,2)),
-              true),
-            0)
-    }
-
-    // interpolated nodes weren't getting labeled.
-    // should expand into
-    // fn main(){let g1_1 = 13; g1_1}}
-    #[test]
-    fn pat_expand_issue_15221(){
-        run_renaming_test(
-            &("macro_rules! inner ( ($e:pat ) => ($e));
-              macro_rules! outer ( ($e:pat ) => (inner!($e)));
-              fn main() { let outer!(g) = 13; g;}",
-              vec!(vec!(0)),
-              true),
-            0)
-    }
-
     // create a really evil test case where a $x appears inside a binding of $x
     // but *shouldn't* bind because it was inserted by a different macro....
     // can't write this test case until we have macro-generating macros.
 
-    // method arg hygiene
-    // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1}
-    #[test]
-    fn method_arg_hygiene(){
-        run_renaming_test(
-            &("macro_rules! inject_x (()=>(x));
-              macro_rules! inject_self (()=>(self));
-              struct A;
-              impl A{fn get_x(&self, x: i32) {self + inject_self!() + inject_x!() + x;} }",
-              vec!(vec!(0),vec!(3)),
-              true),
-            0)
-    }
-
-    // ooh, got another bite?
-    // expands to struct A; impl A {fn thingy(&self_1) {self_1;}}
-    #[test]
-    fn method_arg_hygiene_2(){
-        run_renaming_test(
-            &("struct A;
-              macro_rules! add_method (($T:ty) =>
-              (impl $T {  fn thingy(&self) {self;} }));
-              add_method!(A);",
-              vec!(vec!(0)),
-              true),
-            0)
-    }
-
-    // item fn hygiene
-    // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};}
-    #[test]
-    fn issue_9383(){
-        run_renaming_test(
-            &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex }));
-              fn q(x: i32) { bad_macro!(x); }",
-              vec!(vec!(1),vec!(0)),true),
-            0)
-    }
-
-    // closure arg hygiene (ExprKind::Closure)
-    // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);}
-    #[test]
-    fn closure_arg_hygiene(){
-        run_renaming_test(
-            &("macro_rules! inject_x (()=>(x));
-            fn f(){(|x : i32| {(inject_x!() + x)})(3);}",
-              vec!(vec!(1)),
-              true),
-            0)
-    }
-
-    // macro_rules in method position. Sadly, unimplemented.
-    #[test]
-    fn macro_in_method_posn(){
-        expand_crate_str(
-            "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13}));
-            struct A;
-            impl A{ my_method!(); }
-            fn f(){A.thirteen;}".to_string());
-    }
-
-    // another nested macro
-    // expands to impl Entries {fn size_hint(&self_1) {self_1;}
-    #[test]
-    fn item_macro_workaround(){
-        run_renaming_test(
-            &("macro_rules! item { ($i:item) => {$i}}
-              struct Entries;
-              macro_rules! iterator_impl {
-              () => { item!( impl Entries { fn size_hint(&self) { self;}});}}
-              iterator_impl! { }",
-              vec!(vec!(0)), true),
-            0)
-    }
-
-    // run one of the renaming tests
-    fn run_renaming_test(t: &RenamingTest, test_idx: usize) {
-        let invalid_name = keywords::Invalid.name();
-        let (teststr, bound_connections, bound_ident_check) = match *t {
-            (ref str,ref conns, bic) => (str.to_string(), conns.clone(), bic)
-        };
-        let cr = expand_crate_str(teststr.to_string());
-        let bindings = crate_bindings(&cr);
-        let varrefs = crate_varrefs(&cr);
-
-        // must be one check clause for each binding:
-        assert_eq!(bindings.len(),bound_connections.len());
-        for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
-            let binding_name = mtwt::resolve(bindings[binding_idx]);
-            let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name);
-            // shouldmatch can't name varrefs that don't exist:
-            assert!((shouldmatch.is_empty()) ||
-                    (varrefs.len() > *shouldmatch.iter().max().unwrap()));
-            for (idx,varref) in varrefs.iter().enumerate() {
-                let print_hygiene_debug_info = || {
-                    // good lord, you can't make a path with 0 segments, can you?
-                    let final_varref_ident = match varref.segments.last() {
-                        Some(pathsegment) => pathsegment.identifier,
-                        None => panic!("varref with 0 path segments?")
-                    };
-                    let varref_name = mtwt::resolve(final_varref_ident);
-                    let varref_idents : Vec<ast::Ident>
-                        = varref.segments.iter().map(|s| s.identifier)
-                        .collect();
-                    println!("varref #{}: {:?}, resolves to {}",idx, varref_idents, varref_name);
-                    println!("varref's first segment's string: \"{}\"", final_varref_ident);
-                    println!("binding #{}: {}, resolves to {}",
-                             binding_idx, bindings[binding_idx], binding_name);
-                    mtwt::with_sctable(|x| mtwt::display_sctable(x));
-                };
-                if shouldmatch.contains(&idx) {
-                    // it should be a path of length 1, and it should
-                    // be free-identifier=? or bound-identifier=? to the given binding
-                    assert_eq!(varref.segments.len(),1);
-                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
-                    let varref_marks = mtwt::marksof(varref.segments[0]
-                                                           .identifier
-                                                           .ctxt,
-                                                     invalid_name);
-                    if !(varref_name==binding_name) {
-                        println!("uh oh, should match but doesn't:");
-                        print_hygiene_debug_info();
-                    }
-                    assert_eq!(varref_name,binding_name);
-                    if bound_ident_check {
-                        // we're checking bound-identifier=?, and the marks
-                        // should be the same, too:
-                        assert_eq!(varref_marks,binding_marks.clone());
-                    }
-                } else {
-                    let varref_name = mtwt::resolve(varref.segments[0].identifier);
-                    let fail = (varref.segments.len() == 1)
-                        && (varref_name == binding_name);
-                    // temp debugging:
-                    if fail {
-                        println!("failure on test {}",test_idx);
-                        println!("text of test case: \"{}\"", teststr);
-                        println!("");
-                        println!("uh oh, matches but shouldn't:");
-                        print_hygiene_debug_info();
-                    }
-                    assert!(!fail);
-                }
-            }
-        }
-    }
-
     #[test]
     fn fmt_in_macro_used_inside_module_macro() {
         let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string()));
index 7ac0e8c64c27554844a2809c8bfe8fc58f458692..c9e8715dda6a8a288ae2cebb61284268dca6f507 100644 (file)
 /// The SCTable contains a table of SyntaxContext_'s. It
 /// represents a flattened tree structure, to avoid having
 /// managed pointers everywhere (that caused an ICE).
-/// the mark_memo and rename_memo fields are side-tables
+/// the `marks` and `renames` fields are side-tables
 /// that ensure that adding the same mark to the same context
-/// gives you back the same context as before. This shouldn't
-/// change the semantics--everything here is immutable--but
-/// it should cut down on memory use *a lot*; applying a mark
-/// to a tree containing 50 identifiers would otherwise generate
-/// 50 new contexts
+/// gives you back the same context as before. This should cut
+/// down on memory use *a lot*; applying a mark to a tree containing
+/// 50 identifiers would otherwise generate 50 new contexts.
 pub struct SCTable {
     table: RefCell<Vec<SyntaxContext_>>,
-    mark_memo: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
-    // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and
-    // compared as pair (name, ctxt) and not as an Ident
-    rename_memo: RefCell<HashMap<(SyntaxContext,(Name,SyntaxContext),Name),SyntaxContext>>,
+    marks: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
+    renames: RefCell<HashMap<Name,SyntaxContext>>,
 }
 
 #[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
 pub enum SyntaxContext_ {
     EmptyCtxt,
     Mark (Mrk,SyntaxContext),
-    /// flattening the name and syntaxcontext into the rename...
-    /// HIDDEN INVARIANTS:
-    /// 1) the first name in a Rename node
-    /// can only be a programmer-supplied name.
-    /// 2) Every Rename node with a given Name in the
-    /// "to" slot must have the same name and context
-    /// in the "from" slot. In essence, they're all
-    /// pointers to a single "rename" event node.
-    Rename (Ident,Name,SyntaxContext),
+    Rename (Name),
     /// actually, IllegalCtxt may not be necessary.
     IllegalCtxt
 }
@@ -67,37 +55,39 @@ pub fn apply_mark(m: Mrk, ctxt: SyntaxContext) -> SyntaxContext {
 
 /// Extend a syntax context with a given mark and sctable (explicit memoization)
 fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext {
-    let key = (ctxt, m);
-    *table.mark_memo.borrow_mut().entry(key).or_insert_with(|| {
-        SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))
-    })
+    let ctxts = &mut *table.table.borrow_mut();
+    match ctxts[ctxt.0 as usize] {
+        // Applying the same mark twice is a no-op.
+        Mark(outer_mark, prev_ctxt) if outer_mark == m => return prev_ctxt,
+        _ => *table.marks.borrow_mut().entry((ctxt, m)).or_insert_with(|| {
+            SyntaxContext(idx_push(ctxts, Mark(m, ctxt)))
+        }),
+    }
 }
 
 /// Extend a syntax context with a given rename
-pub fn apply_rename(id: Ident, to:Name,
-                  ctxt: SyntaxContext) -> SyntaxContext {
-    with_sctable(|table| apply_rename_internal(id, to, ctxt, table))
+pub fn apply_rename(from: Ident, to: Name, ident: Ident) -> Ident {
+    with_sctable(|table| apply_rename_internal(from, to, ident, table))
 }
 
 /// Extend a syntax context with a given rename and sctable (explicit memoization)
-fn apply_rename_internal(id: Ident,
-                       to: Name,
-                       ctxt: SyntaxContext,
-                       table: &SCTable) -> SyntaxContext {
-    let key = (ctxt, (id.name, id.ctxt), to);
-
-    *table.rename_memo.borrow_mut().entry(key).or_insert_with(|| {
-            SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))
-    })
+fn apply_rename_internal(from: Ident, to: Name, ident: Ident, table: &SCTable) -> Ident {
+    if (ident.name, ident.ctxt) != (from.name, from.ctxt) {
+        return ident;
+    }
+    let ctxt = *table.renames.borrow_mut().entry(to).or_insert_with(|| {
+        SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(to)))
+    });
+    Ident { ctxt: ctxt, ..ident }
 }
 
 /// Apply a list of renamings to a context
 // if these rename lists get long, it would make sense
 // to consider memoizing this fold. This may come up
 // when we add hygiene to item names.
-pub fn apply_renames(renames: &RenameList, ctxt: SyntaxContext) -> SyntaxContext {
-    renames.iter().fold(ctxt, |ctxt, &(from, to)| {
-        apply_rename(from, to, ctxt)
+pub fn apply_renames(renames: &RenameList, ident: Ident) -> Ident {
+    renames.iter().fold(ident, |ident, &(from, to)| {
+        apply_rename(from, to, ident)
     })
 }
 
@@ -114,8 +104,8 @@ pub fn with_sctable<T, F>(op: F) -> T where
 fn new_sctable_internal() -> SCTable {
     SCTable {
         table: RefCell::new(vec!(EmptyCtxt, IllegalCtxt)),
-        mark_memo: RefCell::new(HashMap::new()),
-        rename_memo: RefCell::new(HashMap::new()),
+        marks: RefCell::new(HashMap::new()),
+        renames: RefCell::new(HashMap::new()),
     }
 }
 
@@ -131,20 +121,18 @@ pub fn display_sctable(table: &SCTable) {
 pub fn clear_tables() {
     with_sctable(|table| {
         *table.table.borrow_mut() = Vec::new();
-        *table.mark_memo.borrow_mut() = HashMap::new();
-        *table.rename_memo.borrow_mut() = HashMap::new();
+        *table.marks.borrow_mut() = HashMap::new();
+        *table.renames.borrow_mut() = HashMap::new();
     });
-    with_resolve_table_mut(|table| *table = HashMap::new());
 }
 
 /// Reset the tables to their initial state
 pub fn reset_tables() {
     with_sctable(|table| {
         *table.table.borrow_mut() = vec!(EmptyCtxt, IllegalCtxt);
-        *table.mark_memo.borrow_mut() = HashMap::new();
-        *table.rename_memo.borrow_mut() = HashMap::new();
+        *table.marks.borrow_mut() = HashMap::new();
+        *table.renames.borrow_mut() = HashMap::new();
     });
-    with_resolve_table_mut(|table| *table = HashMap::new());
 }
 
 /// Add a value to the end of a vec, return its index
@@ -156,103 +144,19 @@ fn idx_push<T>(vec: &mut Vec<T>, val: T) -> u32 {
 /// Resolve a syntax object to a name, per MTWT.
 pub fn resolve(id: Ident) -> Name {
     with_sctable(|sctable| {
-        with_resolve_table_mut(|resolve_table| {
-            resolve_internal(id, sctable, resolve_table)
-        })
+        resolve_internal(id, sctable)
     })
 }
 
-type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
-
-// okay, I admit, putting this in TLS is not so nice:
-// fetch the SCTable from TLS, create one if it doesn't yet exist.
-fn with_resolve_table_mut<T, F>(op: F) -> T where
-    F: FnOnce(&mut ResolveTable) -> T,
-{
-    thread_local!(static RESOLVE_TABLE_KEY: RefCell<ResolveTable> = {
-        RefCell::new(HashMap::new())
-    });
-
-    RESOLVE_TABLE_KEY.with(move |slot| op(&mut *slot.borrow_mut()))
-}
-
 /// Resolve a syntax object to a name, per MTWT.
 /// adding memoization to resolve 500+ seconds in resolve for librustc (!)
-fn resolve_internal(id: Ident,
-                    table: &SCTable,
-                    resolve_table: &mut ResolveTable) -> Name {
-    let key = (id.name, id.ctxt);
-
-    match resolve_table.get(&key) {
-        Some(&name) => return name,
-        None => {}
-    }
-
-    let resolved = {
-        let result = (*table.table.borrow())[id.ctxt.0 as usize];
-        match result {
-            EmptyCtxt => id.name,
-            // ignore marks here:
-            Mark(_,subctxt) =>
-                resolve_internal(Ident::new(id.name, subctxt),
-                                 table, resolve_table),
-            // do the rename if necessary:
-            Rename(Ident{name, ctxt}, toname, subctxt) => {
-                let resolvedfrom =
-                    resolve_internal(Ident::new(name, ctxt),
-                                     table, resolve_table);
-                let resolvedthis =
-                    resolve_internal(Ident::new(id.name, subctxt),
-                                     table, resolve_table);
-                if (resolvedthis == resolvedfrom)
-                    && (marksof_internal(ctxt, resolvedthis, table)
-                        == marksof_internal(subctxt, resolvedthis, table)) {
-                    toname
-                } else {
-                    resolvedthis
-                }
-            }
-            IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt")
-        }
-    };
-    resolve_table.insert(key, resolved);
-    resolved
-}
-
-/// Compute the marks associated with a syntax context.
-pub fn marksof(ctxt: SyntaxContext, stopname: Name) -> Vec<Mrk> {
-    with_sctable(|table| marksof_internal(ctxt, stopname, table))
-}
-
-// the internal function for computing marks
-// it's not clear to me whether it's better to use a [] mutable
-// vector or a cons-list for this.
-fn marksof_internal(ctxt: SyntaxContext,
-                    stopname: Name,
-                    table: &SCTable) -> Vec<Mrk> {
-    let mut result = Vec::new();
-    let mut loopvar = ctxt;
-    loop {
-        let table_entry = (*table.table.borrow())[loopvar.0 as usize];
-        match table_entry {
-            EmptyCtxt => {
-                return result;
-            },
-            Mark(mark, tl) => {
-                xor_push(&mut result, mark);
-                loopvar = tl;
-            },
-            Rename(_,name,tl) => {
-                // see MTWT for details on the purpose of the stopname.
-                // short version: it prevents duplication of effort.
-                if name == stopname {
-                    return result;
-                } else {
-                    loopvar = tl;
-                }
-            }
-            IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt")
-        }
+fn resolve_internal(id: Ident, table: &SCTable) -> Name {
+    match table.table.borrow()[id.ctxt.0 as usize] {
+        EmptyCtxt => id.name,
+        // ignore marks here:
+        Mark(_, subctxt) => resolve_internal(Ident::new(id.name, subctxt), table),
+        Rename(name) => name,
+        IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt")
     }
 }
 
@@ -267,103 +171,16 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
     })
 }
 
-/// Push a name... unless it matches the one on top, in which
-/// case pop and discard (so two of the same marks cancel)
-fn xor_push(marks: &mut Vec<Mrk>, mark: Mrk) {
-    if (!marks.is_empty()) && (*marks.last().unwrap() == mark) {
-        marks.pop().unwrap();
-    } else {
-        marks.push(mark);
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use self::TestSC::*;
     use ast::{EMPTY_CTXT, Ident, Mrk, Name, SyntaxContext};
-    use super::{resolve, xor_push, apply_mark_internal, new_sctable_internal};
-    use super::{apply_rename_internal, apply_renames, marksof_internal, resolve_internal};
-    use super::{SCTable, EmptyCtxt, Mark, Rename, IllegalCtxt};
-    use std::collections::HashMap;
-
-    #[test]
-    fn xorpush_test () {
-        let mut s = Vec::new();
-        xor_push(&mut s, 14);
-        assert_eq!(s.clone(), [14]);
-        xor_push(&mut s, 14);
-        assert_eq!(s.clone(), []);
-        xor_push(&mut s, 14);
-        assert_eq!(s.clone(), [14]);
-        xor_push(&mut s, 15);
-        assert_eq!(s.clone(), [14, 15]);
-        xor_push(&mut s, 16);
-        assert_eq!(s.clone(), [14, 15, 16]);
-        xor_push(&mut s, 16);
-        assert_eq!(s.clone(), [14, 15]);
-        xor_push(&mut s, 15);
-        assert_eq!(s.clone(), [14]);
-    }
+    use super::{resolve, apply_mark_internal, new_sctable_internal};
+    use super::{SCTable, Mark};
 
     fn id(n: u32, s: SyntaxContext) -> Ident {
         Ident::new(Name(n), s)
     }
 
-    // because of the SCTable, I now need a tidy way of
-    // creating syntax objects. Sigh.
-    #[derive(Clone, PartialEq, Debug)]
-    enum TestSC {
-        M(Mrk),
-        R(Ident,Name)
-    }
-
-    // unfold a vector of TestSC values into a SCTable,
-    // returning the resulting index
-    fn unfold_test_sc(tscs : Vec<TestSC> , tail: SyntaxContext, table: &SCTable)
-        -> SyntaxContext {
-        tscs.iter().rev().fold(tail, |tail : SyntaxContext, tsc : &TestSC|
-                  {match *tsc {
-                      M(mrk) => apply_mark_internal(mrk,tail,table),
-                      R(ident,name) => apply_rename_internal(ident,name,tail,table)}})
-    }
-
-    // gather a SyntaxContext back into a vector of TestSCs
-    fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> Vec<TestSC> {
-        let mut result = Vec::new();
-        loop {
-            let table = table.table.borrow();
-            match (*table)[sc.0 as usize] {
-                EmptyCtxt => {return result;},
-                Mark(mrk,tail) => {
-                    result.push(M(mrk));
-                    sc = tail;
-                    continue;
-                },
-                Rename(id,name,tail) => {
-                    result.push(R(id,name));
-                    sc = tail;
-                    continue;
-                }
-                IllegalCtxt => panic!("expected resolvable context, got IllegalCtxt")
-            }
-        }
-    }
-
-    #[test]
-    fn test_unfold_refold(){
-        let mut t = new_sctable_internal();
-
-        let test_sc = vec!(M(3),R(id(101,EMPTY_CTXT),Name(14)),M(9));
-        assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),SyntaxContext(4));
-        {
-            let table = t.table.borrow();
-            assert!((*table)[2] == Mark(9,EMPTY_CTXT));
-            assert!((*table)[3] == Rename(id(101,EMPTY_CTXT),Name(14),SyntaxContext(2)));
-            assert!((*table)[4] == Mark(3,SyntaxContext(3)));
-        }
-        assert_eq!(refold_test_sc(SyntaxContext(4),&t),test_sc);
-    }
-
     // extend a syntax context with a sequence of marks given
     // in a vector. v[0] will be the outermost mark.
     fn unfold_marks(mrks: Vec<Mrk> , tail: SyntaxContext, table: &SCTable)
@@ -383,98 +200,12 @@ fn unfold_marks(mrks: Vec<Mrk> , tail: SyntaxContext, table: &SCTable)
         }
     }
 
-    #[test]
-    fn test_marksof () {
-        let stopname = Name(242);
-        let name1 = Name(243);
-        let mut t = new_sctable_internal();
-        assert_eq!(marksof_internal (EMPTY_CTXT,stopname,&t),Vec::new());
-        // FIXME #5074: ANF'd to dodge nested calls
-        { let ans = unfold_marks(vec!(4,98),EMPTY_CTXT,&mut t);
-         assert_eq! (marksof_internal (ans,stopname,&t), [4, 98]);}
-        // does xoring work?
-        { let ans = unfold_marks(vec!(5,5,16),EMPTY_CTXT,&mut t);
-         assert_eq! (marksof_internal (ans,stopname,&t), [16]);}
-        // does nested xoring work?
-        { let ans = unfold_marks(vec!(5,10,10,5,16),EMPTY_CTXT,&mut t);
-         assert_eq! (marksof_internal (ans, stopname,&t), [16]);}
-        // rename where stop doesn't match:
-        { let chain = vec!(M(9),
-                        R(id(name1.0,
-                             apply_mark_internal (4, EMPTY_CTXT,&mut t)),
-                          Name(100101102)),
-                        M(14));
-         let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
-         assert_eq! (marksof_internal (ans, stopname, &t), [9, 14]);}
-        // rename where stop does match
-        { let name1sc = apply_mark_internal(4, EMPTY_CTXT, &mut t);
-         let chain = vec!(M(9),
-                       R(id(name1.0, name1sc),
-                         stopname),
-                       M(14));
-         let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
-         assert_eq! (marksof_internal (ans, stopname, &t), [9]); }
-    }
-
-
-    #[test]
-    fn resolve_tests () {
-        let a = 40;
-        let mut t = new_sctable_internal();
-        let mut rt = HashMap::new();
-        // - ctxt is MT
-        assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),Name(a));
-        // - simple ignored marks
-        { let sc = unfold_marks(vec!(1,2,3),EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(a));}
-        // - orthogonal rename where names don't match
-        { let sc = unfold_test_sc(vec!(R(id(50,EMPTY_CTXT),Name(51)),M(12)),EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(a));}
-        // - rename where names do match, but marks don't
-        { let sc1 = apply_mark_internal(1,EMPTY_CTXT,&mut t);
-         let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50)),
-                                   M(1),
-                                   M(2)),
-                                 EMPTY_CTXT,&mut t);
-        assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(a));}
-        // - rename where names and marks match
-        { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t);
-         let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50)),M(1),M(2)),EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(50)); }
-        // - rename where names and marks match by literal sharing
-        { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t);
-         let sc = unfold_test_sc(vec!(R(id(a,sc1),Name(50))),sc1,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(50)); }
-        // - two renames of the same var.. can only happen if you use
-        // local-expand to prevent the inner binding from being renamed
-        // during the rename-pass caused by the first:
-        println!("about to run bad test");
-        { let sc = unfold_test_sc(vec!(R(id(a,EMPTY_CTXT),Name(50)),
-                                    R(id(a,EMPTY_CTXT),Name(51))),
-                                  EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), Name(51)); }
-        // the simplest double-rename:
-        { let a_to_a50 = apply_rename_internal(id(a,EMPTY_CTXT),Name(50),EMPTY_CTXT,&mut t);
-         let a50_to_a51 = apply_rename_internal(id(a,a_to_a50),Name(51),a_to_a50,&mut t);
-         assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),Name(51));
-         // mark on the outside doesn't stop rename:
-         let sc = apply_mark_internal(9,a50_to_a51,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),Name(51));
-         // but mark on the inside does:
-         let a50_to_a51_b = unfold_test_sc(vec!(R(id(a,a_to_a50),Name(51)),
-                                              M(9)),
-                                           a_to_a50,
-                                           &mut t);
-         assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),Name(50));}
-    }
-
     #[test]
     fn mtwt_resolve_test(){
         let a = 40;
         assert_eq!(resolve(id(a,EMPTY_CTXT)),Name(a));
     }
 
-
     #[test]
     fn hashing_tests () {
         let mut t = new_sctable_internal();
@@ -484,26 +215,4 @@ fn hashing_tests () {
         assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2));
         // I'm assuming that the rename table will behave the same....
     }
-
-    #[test]
-    fn resolve_table_hashing_tests() {
-        let mut t = new_sctable_internal();
-        let mut rt = HashMap::new();
-        assert_eq!(rt.len(),0);
-        resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
-        assert_eq!(rt.len(),1);
-        resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt);
-        assert_eq!(rt.len(),2);
-        resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
-        assert_eq!(rt.len(),2);
-    }
-
-    #[test]
-    fn new_resolves_test() {
-        let renames = vec!((Ident::with_empty_ctxt(Name(23)),Name(24)),
-                           (Ident::with_empty_ctxt(Name(29)),Name(29)));
-        let new_ctxt1 = apply_renames(&renames,EMPTY_CTXT);
-        assert_eq!(resolve(Ident::new(Name(23),new_ctxt1)),Name(24));
-        assert_eq!(resolve(Ident::new(Name(29),new_ctxt1)),Name(29));
-    }
 }
index 3516f566e8a1ffda8f157786da1479d6def7eb47..a22c3ba48492618347b1c04938f708635e118a3b 100644 (file)
@@ -62,15 +62,16 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
                          sp: Span,
                          attr: &MetaItem,
-                         it: Annotatable) -> Annotatable {
+                         it: Annotatable) -> Vec<Annotatable> {
     match it {
-        Annotatable::Item(it) => {
+        Annotatable::Item(it) => vec![
             Annotatable::Item(P(Item {
                 attrs: it.attrs.clone(),
                 ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
-            }))
-        }
-        Annotatable::ImplItem(it) => {
+            })),
+            Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
+        ],
+        Annotatable::ImplItem(it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Impl(_, _, _, _, _, mut items) => {
@@ -79,8 +80,8 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                     _ => unreachable!("impl parsed to something other than impl")
                 }
             })
-        }
-        Annotatable::TraitItem(it) => {
+        ],
+        Annotatable::TraitItem(it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
                     ItemKind::Trait(_, _, _, mut items) => {
@@ -89,7 +90,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
                     _ => unreachable!("trait parsed to something other than trait")
                 }
             })
-        }
+        ],
     }
 }
 
index 3a3819636691500e36e495288d32143b901ba29d..d17adff007c6335b440c4c42063a753f99f2c91c 100644 (file)
@@ -40,6 +40,8 @@ pub fn main() {
     assert_eq!(Foo2::Bar2, Foo2::Bar2);
     test(None::<Foo2>);
 
+    let _ = Foo3::Bar;
+
     let x = 10i32;
     assert_eq!(x.foo(), 42);
     let x = 10u8;
diff --git a/src/test/run-pass/hygiene.rs b/src/test/run-pass/hygiene.rs
new file mode 100644 (file)
index 0000000..4507ba5
--- /dev/null
@@ -0,0 +1,116 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+fn f() {
+    let x = 0;
+    macro_rules! foo { () => {
+        assert_eq!(x, 0);
+    } }
+
+    let x = 1;
+    foo!();
+}
+
+fn g() {
+    let x = 0;
+    macro_rules! m { ($x:ident) => {
+        macro_rules! m2 { () => { ($x, x) } }
+        let x = 1;
+        macro_rules! m3 { () => { ($x, x) } }
+    } }
+
+    let x = 2;
+    m!(x);
+
+    let x = 3;
+    assert_eq!(m2!(), (2, 0));
+    assert_eq!(m3!(), (2, 1));
+
+    let x = 4;
+    m!(x);
+    assert_eq!(m2!(), (4, 0));
+    assert_eq!(m3!(), (4, 1));
+}
+
+mod foo {
+    macro_rules! m {
+        ($f:ident : |$x:ident| $e:expr) => {
+            pub fn $f() -> (i32, i32) {
+                let x = 0;
+                let $x = 1;
+                (x, $e)
+            }
+        }
+    }
+
+    m!(f: |x| x + 10);
+}
+
+fn interpolated_pattern() {
+    let x = 0;
+    macro_rules! m {
+        ($p:pat, $e:expr) => {
+            let $p = 1;
+            assert_eq!((x, $e), (0, 1));
+        }
+    }
+
+    m!(x, x);
+}
+
+fn patterns_in_macro_generated_macros() {
+    let x = 0;
+    macro_rules! m {
+        ($a:expr, $b:expr) => {
+            assert_eq!(x, 0);
+            let x = $a;
+            macro_rules! n {
+                () => {
+                    (x, $b)
+                }
+            }
+        }
+    }
+
+    let x = 1;
+    m!(2, x);
+
+    let x = 3;
+    assert_eq!(n!(), (2, 1));
+}
+
+fn match_hygiene() {
+    let x = 0;
+
+    macro_rules! m {
+        ($p:pat, $e:expr) => {
+            for result in &[Ok(1), Err(1)] {
+                match *result {
+                    $p => { assert_eq!(($e, x), (1, 0)); }
+                    Err(x) => { assert_eq!(($e, x), (2, 1)); }
+                }
+            }
+        }
+    }
+
+    let x = 2;
+    m!(Ok(x), x);
+}
+
+fn main() {
+    f();
+    g();
+    assert_eq!(foo::f(), (0, 11));
+    interpolated_pattern();
+    patterns_in_macro_generated_macros();
+    match_hygiene();
+}
diff --git a/src/test/run-pass/thread-local-syntax.rs b/src/test/run-pass/thread-local-syntax.rs
new file mode 100644 (file)
index 0000000..a596724
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(missing_docs)]
+//! this tests the syntax of `thread_local!`
+
+thread_local! {
+    // no docs
+    #[allow(unused)]
+    static FOO: i32 = 42;
+    /// docs
+    pub static BAR: String = String::from("bar");
+}
+thread_local!(static BAZ: u32 = 0);
+
+fn main() {}
diff --git a/src/test/rustdoc/issue-34423.rs b/src/test/rustdoc/issue-34423.rs
new file mode 100644 (file)
index 0000000..460462d
--- /dev/null
@@ -0,0 +1,20 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Foo;
+
+pub trait Bar {
+    #[doc(hidden)]
+    fn bar() {}
+}
+
+impl Bar for Foo {
+    fn bar() {}
+}