about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDustin Speckhals <dustin1114@gmail.com>2017-10-29 13:27:06 -0400
committerDustin Speckhals <dustin1114@gmail.com>2017-10-29 13:27:06 -0400
commitd284815f72f20c1edcf05066b376b45ed5390b4e (patch)
treefb285b071a84ebe84d856eb004088f683e94eb82
parent1156455d4278b2d19910b0e198dfcc4560eadcb7 (diff)
parent7d475a28dfa5399600c9b4121193fa57786ab88b (diff)
downloadrust-d284815f72f20c1edcf05066b376b45ed5390b4e.tar.gz
rust-d284815f72f20c1edcf05066b376b45ed5390b4e.zip
Merge branch 'master' into rustfmt-update
-rw-r--r--src/bootstrap/cc_detect.rs35
-rw-r--r--src/ci/docker/arm-android/Dockerfile14
-rw-r--r--src/ci/docker/disabled/dist-aarch64-android/Dockerfile2
-rw-r--r--src/ci/docker/disabled/dist-armv7-android/Dockerfile16
-rw-r--r--src/ci/docker/disabled/dist-i686-android/Dockerfile16
-rw-r--r--src/ci/docker/disabled/dist-x86_64-android/Dockerfile2
-rw-r--r--src/ci/docker/dist-android/Dockerfile12
-rw-r--r--src/ci/docker/scripts/android-sdk.sh52
m---------src/doc/book0
-rw-r--r--src/librustc/hir/def.rs4
-rw-r--r--src/librustc/hir/intravisit.rs1
-rw-r--r--src/librustc/hir/lowering.rs3
-rw-r--r--src/librustc/hir/mod.rs3
-rw-r--r--src/librustc/hir/print.rs7
-rw-r--r--src/librustc/ich/impls_hir.rs4
-rw-r--r--src/librustc/ich/impls_ty.rs6
-rw-r--r--src/librustc/infer/freshen.rs1
-rw-r--r--src/librustc/middle/resolve_lifetime.rs3
-rw-r--r--src/librustc/middle/stability.rs28
-rw-r--r--src/librustc/session/mod.rs15
-rw-r--r--src/librustc/traits/coherence.rs4
-rw-r--r--src/librustc/traits/error_reporting.rs1
-rw-r--r--src/librustc/traits/select.rs12
-rw-r--r--src/librustc/ty/context.rs6
-rw-r--r--src/librustc/ty/error.rs1
-rw-r--r--src/librustc/ty/fast_reject.rs6
-rw-r--r--src/librustc/ty/flags.rs3
-rw-r--r--src/librustc/ty/item_path.rs7
-rw-r--r--src/librustc/ty/layout.rs22
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc/ty/outlives.rs1
-rw-r--r--src/librustc/ty/relate.rs6
-rw-r--r--src/librustc/ty/structural_impls.rs4
-rw-r--r--src/librustc/ty/sty.rs11
-rw-r--r--src/librustc/ty/util.rs6
-rw-r--r--src/librustc/ty/walk.rs3
-rw-r--r--src/librustc/ty/wf.rs3
-rw-r--r--src/librustc/util/ppaux.rs3
-rw-r--r--src/librustc_lint/types.rs3
-rw-r--r--src/librustc_metadata/decoder.rs1
-rw-r--r--src/librustc_metadata/encoder.rs1
-rw-r--r--src/librustc_metadata/schema.rs2
-rw-r--r--src/librustc_passes/ast_validation.rs2
-rw-r--r--src/librustc_privacy/lib.rs16
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs13
-rw-r--r--src/librustc_resolve/lib.rs4
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs7
-rw-r--r--src/librustc_save_analysis/lib.rs3
-rw-r--r--src/librustc_save_analysis/sig.rs17
-rw-r--r--src/librustc_trans/context.rs5
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs16
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs1
-rw-r--r--src/librustc_trans/intrinsic.rs14
-rw-r--r--src/librustc_trans/mir/constant.rs6
-rw-r--r--src/librustc_trans/mir/lvalue.rs18
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/librustc_trans/trans_item.rs1
-rw-r--r--src/librustc_trans/type_of.rs8
-rw-r--r--src/librustc_trans_utils/collector.rs4
-rw-r--r--src/librustc_trans_utils/common.rs13
-rw-r--r--src/librustc_trans_utils/lib.rs2
-rw-r--r--src/librustc_trans_utils/trans_item.rs1
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustc_typeck/check/cast.rs64
-rw-r--r--src/librustc_typeck/check/method/probe.rs3
-rw-r--r--src/librustc_typeck/check/method/suggest.rs1
-rw-r--r--src/librustc_typeck/coherence/inherent_impls.rs3
-rw-r--r--src/librustc_typeck/coherence/orphan.rs11
-rw-r--r--src/librustc_typeck/collect.rs9
-rw-r--r--src/librustc_typeck/variance/constraints.rs2
-rw-r--r--src/librustdoc/clean/mod.rs17
-rw-r--r--src/librustdoc/html/item_type.rs7
-rw-r--r--src/librustdoc/html/render.rs4
-rw-r--r--src/librustdoc/passes/mod.rs2
-rw-r--r--src/libstd/process.rs83
-rw-r--r--src/libsyntax/ast.rs5
-rw-r--r--src/libsyntax/feature_gate.rs27
-rw-r--r--src/libsyntax/fold.rs1
-rw-r--r--src/libsyntax/json.rs26
-rw-r--r--src/libsyntax/parse/parser.rs22
-rw-r--r--src/libsyntax/print/pprust.rs7
-rw-r--r--src/libsyntax/visit.rs1
-rw-r--r--src/test/compile-fail/extern-types-distinct-types.rs22
-rw-r--r--src/test/compile-fail/extern-types-not-sync-send.rs28
-rw-r--r--src/test/compile-fail/extern-types-unsized.rs43
-rw-r--r--src/test/compile-fail/feature-gate-extern_types.rs15
-rw-r--r--src/test/compile-fail/issue-27842.rs2
-rw-r--r--src/test/run-make/extern-fn-with-extern-types/Makefile5
-rw-r--r--src/test/run-make/extern-fn-with-extern-types/ctest.c17
-rw-r--r--src/test/run-make/extern-fn-with-extern-types/test.rs27
-rw-r--r--src/test/run-pass/extern-types-inherent-impl.rs27
-rw-r--r--src/test/run-pass/extern-types-manual-sync-send.rs28
-rw-r--r--src/test/run-pass/extern-types-pointer-cast.rs40
-rw-r--r--src/test/run-pass/extern-types-size_of_val.rs26
-rw-r--r--src/test/run-pass/extern-types-thin-pointer.rs51
-rw-r--r--src/test/run-pass/extern-types-trait-impl.rs35
-rw-r--r--src/test/ui/lint/unused_parens_json_suggestion.stderr2
-rw-r--r--src/test/ui/lint/use_suggestion_json.rs21
-rw-r--r--src/test/ui/lint/use_suggestion_json.stderr2
-rw-r--r--src/tools/compiletest/src/json.rs19
100 files changed, 981 insertions, 212 deletions
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index 6e3e3c92029..e531fdaf292 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -84,7 +84,7 @@ pub fn find(build: &mut Build) {
         if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
             cfg.compiler(cc);
         } else {
-            set_compiler(&mut cfg, "gcc", target, config, build);
+            set_compiler(&mut cfg, Language::C, target, config, build);
         }
 
         let compiler = cfg.get_compiler();
@@ -112,7 +112,7 @@ pub fn find(build: &mut Build) {
         if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
             cfg.compiler(cxx);
         } else {
-            set_compiler(&mut cfg, "g++", host, config, build);
+            set_compiler(&mut cfg, Language::CPlusPlus, host, config, build);
         }
         let compiler = cfg.get_compiler();
         build.verbose(&format!("CXX_{} = {:?}", host, compiler.path()));
@@ -121,7 +121,7 @@ pub fn find(build: &mut Build) {
 }
 
 fn set_compiler(cfg: &mut cc::Build,
-                gnu_compiler: &str,
+                compiler: Language,
                 target: Interned<String>,
                 config: Option<&Target>,
                 build: &Build) {
@@ -132,7 +132,7 @@ fn set_compiler(cfg: &mut cc::Build,
         t if t.contains("android") => {
             if let Some(ndk) = config.and_then(|c| c.ndk.as_ref()) {
                 let target = target.replace("armv7", "arm");
-                let compiler = format!("{}-{}", target, gnu_compiler);
+                let compiler = format!("{}-{}", target, compiler.clang());
                 cfg.compiler(ndk.join("bin").join(compiler));
             }
         }
@@ -141,6 +141,7 @@ fn set_compiler(cfg: &mut cc::Build,
         // which is a gcc version from ports, if this is the case.
         t if t.contains("openbsd") => {
             let c = cfg.get_compiler();
+            let gnu_compiler = compiler.gcc();
             if !c.path().ends_with(gnu_compiler) {
                 return
             }
@@ -183,3 +184,29 @@ fn set_compiler(cfg: &mut cc::Build,
         _ => {}
     }
 }
+
+/// The target programming language for a native compiler.
+enum Language {
+    /// The compiler is targeting C.
+    C,
+    /// The compiler is targeting C++.
+    CPlusPlus,
+}
+
+impl Language {
+    /// Obtains the name of a compiler in the GCC collection.
+    fn gcc(self) -> &'static str {
+        match self {
+            Language::C => "gcc",
+            Language::CPlusPlus => "g++",
+        }
+    }
+
+    /// Obtains the name of a compiler in the clang suite.
+    fn clang(self) -> &'static str {
+        match self {
+            Language::C => "clang",
+            Language::CPlusPlus => "clang++",
+        }
+    }
+}
diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile
index 49d07d28d3c..f2773a720cf 100644
--- a/src/ci/docker/arm-android/Dockerfile
+++ b/src/ci/docker/arm-android/Dockerfile
@@ -5,21 +5,27 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip arm 9
+    download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm 14
 
+# Note:
+# Do not upgrade to `openjdk-9-jre-headless`, as it will cause certificate error
+# when installing the Android SDK (see PR #45193). This is unfortunate, but
+# every search result suggested either disabling HTTPS or replacing JDK 9 by
+# JDK 8 as the solution (e.g. https://stackoverflow.com/q/41421340). :|
 RUN dpkg --add-architecture i386 && \
     apt-get update && \
     apt-get install -y --no-install-recommends \
   libgl1-mesa-glx \
   libpulse0 \
   libstdc++6:i386 \
-  openjdk-9-jre-headless \
+  openjdk-8-jre-headless \
   tzdata
 
 COPY scripts/android-sdk.sh /scripts/
 RUN . /scripts/android-sdk.sh && \
-    download_and_create_avd tools_r25.2.5-linux.zip armeabi-v7a 18
+    download_and_create_avd 4333796 armeabi-v7a 18
 
+ENV PATH=$PATH:/android/sdk/emulator
 ENV PATH=$PATH:/android/sdk/tools
 ENV PATH=$PATH:/android/sdk/platform-tools
 
@@ -27,7 +33,7 @@ ENV TARGETS=arm-linux-androideabi
 
 ENV RUST_CONFIGURE_ARGS \
       --target=$TARGETS \
-      --arm-linux-androideabi-ndk=/android/ndk/arm-9
+      --arm-linux-androideabi-ndk=/android/ndk/arm-14
 
 ENV SCRIPT python2.7 ../x.py test --target $TARGETS
 
diff --git a/src/ci/docker/disabled/dist-aarch64-android/Dockerfile b/src/ci/docker/disabled/dist-aarch64-android/Dockerfile
index 20d823a3d73..ce5e8cfaf09 100644
--- a/src/ci/docker/disabled/dist-aarch64-android/Dockerfile
+++ b/src/ci/docker/disabled/dist-aarch64-android/Dockerfile
@@ -5,7 +5,7 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip arm64 21
+    download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip arm64 21
 
 ENV PATH=$PATH:/android/ndk/arm64-21/bin
 
diff --git a/src/ci/docker/disabled/dist-armv7-android/Dockerfile b/src/ci/docker/disabled/dist-armv7-android/Dockerfile
index 3435d641a13..3177fa2147f 100644
--- a/src/ci/docker/disabled/dist-armv7-android/Dockerfile
+++ b/src/ci/docker/disabled/dist-armv7-android/Dockerfile
@@ -5,17 +5,17 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_ndk android-ndk-r13b-linux-x86_64.zip && \
-    make_standalone_toolchain arm 9 && \
+    download_ndk android-ndk-r15c-linux-x86_64.zip && \
+    make_standalone_toolchain arm 14 && \
     make_standalone_toolchain arm 21 && \
     remove_ndk
 
 RUN chmod 777 /android/ndk && \
     ln -s /android/ndk/arm-21 /android/ndk/arm
 
-ENV PATH=$PATH:/android/ndk/arm-9/bin
+ENV PATH=$PATH:/android/ndk/arm-14/bin
 
-ENV DEP_Z_ROOT=/android/ndk/arm-9/sysroot/usr/
+ENV DEP_Z_ROOT=/android/ndk/arm-14/sysroot/usr/
 
 ENV HOSTS=armv7-linux-androideabi
 
@@ -27,18 +27,18 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-extended \
       --enable-cargo-openssl-static
 
-# We support api level 9, but api level 21 is required to build llvm. To
+# We support api level 14, but api level 21 is required to build llvm. To
 # overcome this problem we use a ndk with api level 21 to build llvm and then
-# switch to a ndk with api level 9 to complete the build. When the linker is
+# switch to a ndk with api level 14 to complete the build. When the linker is
 # invoked there are missing symbols (like sigsetempty, not available with api
-# level 9), the default linker behavior is to generate an error, to allow the
+# level 14), the default linker behavior is to generate an error, to allow the
 # build to finish we use --warn-unresolved-symbols. Note that the missing
 # symbols does not affect std, only the compiler (llvm) and cargo (openssl).
 ENV SCRIPT \
   python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
   (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
     rm /android/ndk/arm && \
-    ln -s /android/ndk/arm-9 /android/ndk/arm && \
+    ln -s /android/ndk/arm-14 /android/ndk/arm && \
     python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/disabled/dist-i686-android/Dockerfile b/src/ci/docker/disabled/dist-i686-android/Dockerfile
index 4bb7053760f..ace9c4feb4f 100644
--- a/src/ci/docker/disabled/dist-i686-android/Dockerfile
+++ b/src/ci/docker/disabled/dist-i686-android/Dockerfile
@@ -5,17 +5,17 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_ndk android-ndk-r13b-linux-x86_64.zip && \
-    make_standalone_toolchain x86 9 && \
+    download_ndk android-ndk-r15c-linux-x86_64.zip && \
+    make_standalone_toolchain x86 14 && \
     make_standalone_toolchain x86 21 && \
     remove_ndk
 
 RUN chmod 777 /android/ndk && \
     ln -s /android/ndk/x86-21 /android/ndk/x86
 
-ENV PATH=$PATH:/android/ndk/x86-9/bin
+ENV PATH=$PATH:/android/ndk/x86-14/bin
 
-ENV DEP_Z_ROOT=/android/ndk/x86-9/sysroot/usr/
+ENV DEP_Z_ROOT=/android/ndk/x86-14/sysroot/usr/
 
 ENV HOSTS=i686-linux-android
 
@@ -27,18 +27,18 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-extended \
       --enable-cargo-openssl-static
 
-# We support api level 9, but api level 21 is required to build llvm. To
+# We support api level 14, but api level 21 is required to build llvm. To
 # overcome this problem we use a ndk with api level 21 to build llvm and then
-# switch to a ndk with api level 9 to complete the build. When the linker is
+# switch to a ndk with api level 14 to complete the build. When the linker is
 # invoked there are missing symbols (like sigsetempty, not available with api
-# level 9), the default linker behavior is to generate an error, to allow the
+# level 14), the default linker behavior is to generate an error, to allow the
 # build to finish we use --warn-unresolved-symbols. Note that the missing
 # symbols does not affect std, only the compiler (llvm) and cargo (openssl).
 ENV SCRIPT \
   python2.7 ../x.py build src/llvm --host $HOSTS --target $HOSTS && \
   (export RUSTFLAGS="\"-C link-arg=-Wl,--warn-unresolved-symbols\""; \
     rm /android/ndk/x86 && \
-    ln -s /android/ndk/x86-9 /android/ndk/x86 && \
+    ln -s /android/ndk/x86-14 /android/ndk/x86 && \
     python2.7 ../x.py dist --host $HOSTS --target $HOSTS)
 
 COPY scripts/sccache.sh /scripts/
diff --git a/src/ci/docker/disabled/dist-x86_64-android/Dockerfile b/src/ci/docker/disabled/dist-x86_64-android/Dockerfile
index 525b218417b..322d26f0adc 100644
--- a/src/ci/docker/disabled/dist-x86_64-android/Dockerfile
+++ b/src/ci/docker/disabled/dist-x86_64-android/Dockerfile
@@ -5,7 +5,7 @@ RUN sh /scripts/android-base-apt-get.sh
 
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_and_make_toolchain android-ndk-r13b-linux-x86_64.zip x86_64 21
+    download_and_make_toolchain android-ndk-r15c-linux-x86_64.zip x86_64 21
 
 ENV PATH=$PATH:/android/ndk/x86_64-21/bin
 
diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile
index a36f7fc1ac5..5d7545a3c2a 100644
--- a/src/ci/docker/dist-android/Dockerfile
+++ b/src/ci/docker/dist-android/Dockerfile
@@ -6,9 +6,9 @@ RUN sh /scripts/android-base-apt-get.sh
 # ndk
 COPY scripts/android-ndk.sh /scripts/
 RUN . /scripts/android-ndk.sh && \
-    download_ndk android-ndk-r13b-linux-x86_64.zip && \
-    make_standalone_toolchain arm 9 && \
-    make_standalone_toolchain x86 9 && \
+    download_ndk android-ndk-r15c-linux-x86_64.zip && \
+    make_standalone_toolchain arm 14 && \
+    make_standalone_toolchain x86 14 && \
     make_standalone_toolchain arm64 21 && \
     make_standalone_toolchain x86_64 21 && \
     remove_ndk
@@ -23,9 +23,9 @@ ENV TARGETS=$TARGETS,x86_64-linux-android
 ENV RUST_CONFIGURE_ARGS \
       --target=$TARGETS \
       --enable-extended \
-      --arm-linux-androideabi-ndk=/android/ndk/arm-9 \
-      --armv7-linux-androideabi-ndk=/android/ndk/arm-9 \
-      --i686-linux-android-ndk=/android/ndk/x86-9 \
+      --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
+      --armv7-linux-androideabi-ndk=/android/ndk/arm-14 \
+      --i686-linux-android-ndk=/android/ndk/x86-14 \
       --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
       --x86_64-linux-android-ndk=/android/ndk/x86_64-21
 
diff --git a/src/ci/docker/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh
index 3aa2b9d58d5..99c5776c2e8 100644
--- a/src/ci/docker/scripts/android-sdk.sh
+++ b/src/ci/docker/scripts/android-sdk.sh
@@ -10,40 +10,40 @@
 
 set -ex
 
-URL=https://dl.google.com/android/repository
+export ANDROID_HOME=/android/sdk
+PATH=$PATH:"${ANDROID_HOME}/tools/bin"
 
 download_sdk() {
-    mkdir -p /android/sdk
-    cd /android/sdk
-    curl -fO $URL/$1
-    unzip -q $1
-    rm -rf $1
+    mkdir -p /android
+    curl -fo sdk.zip "https://dl.google.com/android/repository/sdk-tools-linux-$1.zip"
+    unzip -q sdk.zip -d "$ANDROID_HOME"
+    rm -f sdk.zip
 }
 
 download_sysimage() {
-    # See https://developer.android.com/studio/tools/help/android.html
     abi=$1
     api=$2
 
-    filter="platform-tools,android-$api"
-    filter="$filter,sys-img-$abi-android-$api"
-
-    # Keep printing yes to accept the licenses
-    while true; do echo yes; sleep 10; done | \
-        /android/sdk/tools/android update sdk -a --no-ui \
-            --filter "$filter" --no-https
+    # See https://developer.android.com/studio/command-line/sdkmanager.html for
+    # usage of `sdkmanager`.
+    #
+    # The output from sdkmanager is so noisy that it will occupy all of the 4 MB
+    # log extremely quickly. Thus we must silence all output.
+    yes | sdkmanager --licenses > /dev/null
+    sdkmanager platform-tools emulator \
+        "platforms;android-$api" \
+        "system-images;android-$api;default;$abi" > /dev/null
 }
 
 create_avd() {
-    # See https://developer.android.com/studio/tools/help/android.html
     abi=$1
     api=$2
 
-    echo no | \
-        /android/sdk/tools/android create avd \
-            --name $abi-$api \
-            --target android-$api \
-            --abi $abi
+    # See https://developer.android.com/studio/command-line/avdmanager.html for
+    # usage of `avdmanager`.
+    echo no | avdmanager create avd \
+        -n "$abi-$api" \
+        -k "system-images;android-$api;default;$abi"
 }
 
 download_and_create_avd() {
@@ -51,3 +51,15 @@ download_and_create_avd() {
     download_sysimage $2 $3
     create_avd $2 $3
 }
+
+# Usage:
+#
+#       setup_android_sdk 4333796 armeabi-v7a 18
+#
+# 4333796 =>
+#   SDK tool version.
+#   Copy from https://developer.android.com/studio/index.html#command-tools
+# armeabi-v7a =>
+#   System image ABI
+# 18 =>
+#   Android API Level (18 = Android 4.3 = Jelly Bean MR2)
diff --git a/src/doc/book b/src/doc/book
-Subproject 808f482db94391fca1e04a9692b59e9eda8cfef
+Subproject 7db393dae740d84775b73f403123c866e94e3a5
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 4e0c6479abf..64bcdc7920a 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -35,6 +35,7 @@ pub enum Def {
     Variant(DefId),
     Trait(DefId),
     TyAlias(DefId),
+    TyForeign(DefId),
     AssociatedTy(DefId),
     PrimTy(hir::PrimTy),
     TyParam(DefId),
@@ -152,7 +153,7 @@ impl Def {
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
             Def::AssociatedConst(id) | Def::Macro(id, ..) |
-            Def::GlobalAsm(id) => {
+            Def::GlobalAsm(id) | Def::TyForeign(id) => {
                 id
             }
 
@@ -186,6 +187,7 @@ impl Def {
             Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
             Def::Union(..) => "union",
             Def::Trait(..) => "trait",
+            Def::TyForeign(..) => "foreign type",
             Def::Method(..) => "method",
             Def::Const(..) => "constant",
             Def::AssociatedConst(..) => "associated constant",
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index d99d7cd897b..ae25924ab42 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -704,6 +704,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v
             }
         }
         ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
+        ForeignItemType => (),
     }
 
     walk_list!(visitor, visit_attribute, &foreign_item.attrs);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 184e6646558..3834852cac5 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1722,6 +1722,9 @@ impl<'a> LoweringContext<'a> {
                     ForeignItemKind::Static(ref t, m) => {
                         hir::ForeignItemStatic(this.lower_ty(t), m)
                     }
+                    ForeignItemKind::Ty => {
+                        hir::ForeignItemType
+                    }
                 },
                 vis: this.lower_visibility(&i.vis, None),
                 span: i.span,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index fb3fc8a2da4..ca5ffe83048 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1912,6 +1912,8 @@ pub enum ForeignItem_ {
     /// A foreign static item (`static ext: u8`), with optional mutability
     /// (the boolean is true when mutable)
     ForeignItemStatic(P<Ty>, bool),
+    /// A foreign type
+    ForeignItemType,
 }
 
 impl ForeignItem_ {
@@ -1919,6 +1921,7 @@ impl ForeignItem_ {
         match *self {
             ForeignItemFn(..) => "foreign function",
             ForeignItemStatic(..) => "foreign static item",
+            ForeignItemType => "foreign type",
         }
     }
 }
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index b4614873550..24a0b5fcea9 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -478,6 +478,13 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
             }
+            hir::ForeignItemType => {
+                self.head(&visibility_qualified(&item.vis, "type"))?;
+                self.print_name(item.name)?;
+                self.s.word(";")?;
+                self.end()?; // end the head-ibox
+                self.end() // end the outer cbox
+            }
         }
     }
 
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 994f0bd16b1..181b97aa7b5 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -977,7 +977,8 @@ impl_stable_hash_for!(struct hir::ForeignItem {
 
 impl_stable_hash_for!(enum hir::ForeignItem_ {
     ForeignItemFn(fn_decl, arg_names, generics),
-    ForeignItemStatic(ty, is_mutbl)
+    ForeignItemStatic(ty, is_mutbl),
+    ForeignItemType
 });
 
 impl_stable_hash_for!(enum hir::Stmt_ {
@@ -1086,6 +1087,7 @@ impl_stable_hash_for!(enum hir::def::Def {
     PrimTy(prim_ty),
     TyParam(def_id),
     SelfTy(trait_def_id, impl_def_id),
+    TyForeign(def_id),
     Fn(def_id),
     Const(def_id),
     Static(def_id, is_mutbl),
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 8a8dfbabbe1..48d3017f597 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -610,8 +610,7 @@ for ty::TypeVariants<'gcx>
                 def_id.hash_stable(hcx, hasher);
                 closure_substs.hash_stable(hcx, hasher);
             }
-            TyGenerator(def_id, closure_substs, interior)
-             => {
+            TyGenerator(def_id, closure_substs, interior) => {
                 def_id.hash_stable(hcx, hasher);
                 closure_substs.hash_stable(hcx, hasher);
                 interior.hash_stable(hcx, hasher);
@@ -630,6 +629,9 @@ for ty::TypeVariants<'gcx>
             TyParam(param_ty) => {
                 param_ty.hash_stable(hcx, hasher);
             }
+            TyForeign(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
             TyInfer(..) => {
                 bug!("ty::TypeVariants::hash_stable() - Unexpected variant {:?}.", *self)
             }
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index c274f8bda9f..41e7dffe54d 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::TyNever |
             ty::TyTuple(..) |
             ty::TyProjection(..) |
+            ty::TyForeign(..) |
             ty::TyParam(..) |
             ty::TyAnon(..) => {
                 t.super_fold_with(self)
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index dc912f1c1b6..ee0e580920e 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -365,6 +365,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             hir::ForeignItemStatic(..) => {
                 intravisit::walk_foreign_item(self, item);
             }
+            hir::ForeignItemType => {
+                intravisit::walk_foreign_item(self, item);
+            }
         }
     }
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 4e4fc8b3118..b30d5e38488 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -18,8 +18,9 @@ use hir::def::Def;
 use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use ty::{self, TyCtxt};
 use middle::privacy::AccessLevels;
+use session::DiagnosticMessageId;
 use syntax::symbol::Symbol;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::{Span, MultiSpan, DUMMY_SP};
 use syntax::ast;
 use syntax::ast::{NodeId, Attribute};
 use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
@@ -597,8 +598,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                            feature.as_str(), &r),
                     None => format!("use of unstable library feature '{}'", &feature)
                 };
-                emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span,
-                                 GateIssue::Library(Some(issue)), &msg);
+
+
+                let msp: MultiSpan = span.into();
+                let cm = &self.sess.parse_sess.codemap();
+                let span_key = msp.primary_span().and_then(|sp: Span|
+                    if sp != DUMMY_SP {
+                        let file = cm.lookup_char_pos(sp.lo()).file;
+                        if file.name.starts_with("<") && file.name.ends_with(" macros>") {
+                            None
+                        } else {
+                            Some(span)
+                        }
+                    } else {
+                        None
+                    }
+                );
+
+                let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone());
+                let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id);
+                if fresh {
+                    emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span,
+                                     GateIssue::Library(Some(issue)), &msg);
+                }
             }
             Some(_) => {
                 // Stable APIs are always ok to call and deprecated APIs are
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index c87881341da..be35cc8e4a1 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -75,10 +75,10 @@ pub struct Session {
     pub working_dir: (String, bool),
     pub lint_store: RefCell<lint::LintStore>,
     pub buffered_lints: RefCell<Option<lint::LintBuffer>>,
-    /// Set of (LintId, Option<Span>, message) tuples tracking lint
+    /// Set of (DiagnosticId, Option<Span>, message) tuples tracking
     /// (sub)diagnostics that have been set once, but should not be set again,
-    /// in order to avoid redundantly verbose output (Issue #24690).
-    pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Option<Span>, String)>>,
+    /// in order to avoid redundantly verbose output (Issue #24690, #44953).
+    pub one_time_diagnostics: RefCell<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
     pub plugin_llvm_passes: RefCell<Vec<String>>,
     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
     pub crate_types: RefCell<Vec<config::CrateType>>,
@@ -164,6 +164,13 @@ enum DiagnosticBuilderMethod {
     // add more variants as needed to support one-time diagnostics
 }
 
+/// Diagnostic message id - used in order to avoid emitting the same message more than once
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum DiagnosticMessageId {
+    LintId(lint::LintId),
+    StabilityId(u32)
+}
+
 impl Session {
     pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
         match *self.crate_disambiguator.borrow() {
@@ -360,7 +367,7 @@ impl Session {
                 do_method()
             },
             _ => {
-                let lint_id = lint::LintId::of(lint);
+                let lint_id = DiagnosticMessageId::LintId(lint::LintId::of(lint));
                 let id_span_message = (lint_id, span, message.to_owned());
                 let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message);
                 if fresh {
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index dc5ce735324..10a32c26e74 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -304,6 +304,10 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool {
             def.did.is_local()
         }
 
+        ty::TyForeign(did) => {
+            did.is_local()
+        }
+
         ty::TyDynamic(ref tt, ..) => {
             tt.principal().map_or(false, |p| p.def_id().is_local())
         }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 030b7e4f646..e2b23c12cf1 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -255,6 +255,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     AdtKind::Enum => Some(17),
                 },
                 ty::TyGenerator(..) => Some(18),
+                ty::TyForeign(..) => Some(19),
                 ty::TyInfer(..) | ty::TyError => None
             }
         }
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index cec79faff31..6c573acf07d 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1705,6 +1705,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     // say nothing; a candidate may be added by
                     // `assemble_candidates_from_object_ty`.
                 }
+                ty::TyForeign(..) => {
+                    // Since the contents of foreign types is unknown,
+                    // we don't add any `..` impl. Default traits could
+                    // still be provided by a manual implementation for
+                    // this trait and type.
+                }
                 ty::TyParam(..) |
                 ty::TyProjection(..) => {
                     // In these cases, we don't know what the actual
@@ -2022,7 +2028,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) => Never,
+            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
 
             ty::TyTuple(tys, _) => {
                 Where(ty::Binder(tys.last().into_iter().cloned().collect()))
@@ -2066,7 +2072,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyGenerator(..) |
+            ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
+            ty::TyGenerator(..) | ty::TyForeign(..) |
             ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
                 Never
             }
@@ -2148,6 +2155,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             ty::TyDynamic(..) |
             ty::TyParam(..) |
+            ty::TyForeign(..) |
             ty::TyProjection(..) |
             ty::TyInfer(ty::TyVar(_)) |
             ty::TyInfer(ty::FreshTy(_)) |
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index ebd9fa93236..6ab81a41d68 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1610,7 +1610,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     pub fn print_debug_stats(self) {
         sty_debug_print!(
             self,
-            TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator,
+            TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyForeign,
             TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
 
         println!("Substs interner: #{}", self.interners.substs.borrow().len());
@@ -1861,6 +1861,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyAdt(def, substs))
     }
 
+    pub fn mk_foreign(self, def_id: DefId) -> Ty<'tcx> {
+        self.mk_ty(TyForeign(def_id))
+    }
+
     pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
         let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
         let adt_def = self.adt_def(def_id);
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 52a8389bd8f..5cfa72c0712 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -182,6 +182,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
 
             ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
+            ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
             ty::TyArray(_, n) => {
                 if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
                     format!("array of {} elements", n)
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 490bfe78a9a..138f6af77c6 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -49,6 +49,7 @@ pub enum SimplifiedTypeGen<D>
     AnonSimplifiedType(D),
     FunctionSimplifiedType(usize),
     ParameterSimplifiedType,
+    ForeignSimplifiedType(DefId),
 }
 
 /// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
@@ -113,6 +114,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyAnon(def_id, _) => {
             Some(AnonSimplifiedType(def_id))
         }
+        ty::TyForeign(def_id) => {
+            Some(ForeignSimplifiedType(def_id))
+        }
         ty::TyInfer(_) | ty::TyError => None,
     }
 }
@@ -140,6 +144,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
             AnonSimplifiedType(d) => AnonSimplifiedType(map(d)),
             FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
             ParameterSimplifiedType => ParameterSimplifiedType,
+            ForeignSimplifiedType(d) => ForeignSimplifiedType(d),
         }
     }
 }
@@ -172,6 +177,7 @@ impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
             GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
             AnonSimplifiedType(d) => d.hash_stable(hcx, hasher),
             FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
+            ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),
         }
     }
 }
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 9ece719c764..63c646dbd23 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -63,7 +63,8 @@ impl FlagComputation {
             &ty::TyFloat(_) |
             &ty::TyUint(_) |
             &ty::TyNever |
-            &ty::TyStr => {
+            &ty::TyStr |
+            &ty::TyForeign(..) => {
             }
 
             // You might think that we could just return TyError for
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index a8ccb3e269f..98c55331f8a 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -281,6 +281,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
+            ty::TyForeign(did) => self.push_item_path(buffer, did),
+
             ty::TyBool |
             ty::TyChar |
             ty::TyInt(_) |
@@ -344,8 +346,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
                                       .next(),
 
         ty::TyFnDef(def_id, _) |
-        ty::TyClosure(def_id, _) => Some(def_id),
-        ty::TyGenerator(def_id, _, _) => Some(def_id),
+        ty::TyClosure(def_id, _) |
+        ty::TyGenerator(def_id, _, _) |
+        ty::TyForeign(def_id) => Some(def_id),
 
         ty::TyBool |
         ty::TyChar |
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 1709f9ed2df..491fa2a240c 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -1141,14 +1141,15 @@ impl<'a, 'tcx> Layout {
                 Ok(Scalar { value: Pointer, non_zero: non_zero })
             } else {
                 let unsized_part = tcx.struct_tail(pointee);
-                let meta = match unsized_part.sty {
-                    ty::TySlice(_) | ty::TyStr => {
-                        Int(dl.ptr_sized_integer())
-                    }
-                    ty::TyDynamic(..) => Pointer,
-                    _ => return Err(LayoutError::Unknown(unsized_part))
-                };
-                Ok(FatPointer { metadata: meta, non_zero: non_zero })
+                match unsized_part.sty {
+                    ty::TySlice(_) | ty::TyStr => Ok(FatPointer {
+                        metadata: Int(dl.ptr_sized_integer()),
+                        non_zero: non_zero
+                    }),
+                    ty::TyDynamic(..) => Ok(FatPointer { metadata: Pointer, non_zero: non_zero }),
+                    ty::TyForeign(..) => Ok(Scalar { value: Pointer, non_zero: non_zero }),
+                    _ => Err(LayoutError::Unknown(unsized_part)),
+                }
             }
         };
 
@@ -1239,7 +1240,7 @@ impl<'a, 'tcx> Layout {
                     non_zero: false
                 }
             }
-            ty::TyDynamic(..) => {
+            ty::TyDynamic(..) | ty::TyForeign(..) => {
                 let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
                   StructKind::AlwaysSizedUnivariant, ty)?;
                 unit.sized = false;
@@ -2252,7 +2253,8 @@ impl<'a, 'tcx> TyLayout<'tcx> {
             ty::TyFnPtr(_) |
             ty::TyNever |
             ty::TyFnDef(..) |
-            ty::TyDynamic(..) => {
+            ty::TyDynamic(..) |
+            ty::TyForeign(..) => {
                 bug!("TyLayout::field_type({:?}): not applicable", self)
             }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 9b239a35f90..b3f2886cdf9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1784,7 +1784,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                 vec![]
             }
 
-            TyStr | TyDynamic(..) | TySlice(_) | TyError => {
+            TyStr | TyDynamic(..) | TySlice(_) | TyForeign(..) | TyError => {
                 // these are never sized - return the target type
                 vec![ty]
             }
diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs
index 5e1dc485d42..707137649d7 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -142,6 +142,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             ty::TyNever |           // ...
             ty::TyAdt(..) |         // OutlivesNominalType
             ty::TyAnon(..) |        // OutlivesNominalType (ish)
+            ty::TyForeign(..) |     // OutlivesNominalType
             ty::TyStr |             // OutlivesScalar (ish)
             ty::TyArray(..) |       // ...
             ty::TySlice(..) |       // ...
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 309880ba063..376cdc462e8 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -381,6 +381,12 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
             Ok(tcx.mk_adt(a_def, substs))
         }
 
+        (&ty::TyForeign(a_id), &ty::TyForeign(b_id))
+            if a_id == b_id =>
+        {
+            Ok(tcx.mk_foreign(a_id))
+        }
+
         (&ty::TyDynamic(ref a_obj, ref a_region), &ty::TyDynamic(ref b_obj, ref b_region)) => {
             let region_bound = relation.with_cause(Cause::ExistentialRegionBound,
                                                        |relation| {
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 54d55748c8e..5f1448cd1f1 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -676,7 +676,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)),
             ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
             ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
-            ty::TyParam(..) | ty::TyNever => return self
+            ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => return self
         };
 
         if self.sty == sty {
@@ -710,7 +710,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
             ty::TyAnon(_, ref substs) => substs.visit_with(visitor),
             ty::TyBool | ty::TyChar | ty::TyStr | ty::TyInt(_) |
             ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
-            ty::TyParam(..) | ty::TyNever => false,
+            ty::TyParam(..) | ty::TyNever | ty::TyForeign(..) => false,
         }
     }
 
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 064627c21bf..d0ac7d0183a 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -104,6 +104,8 @@ pub enum TypeVariants<'tcx> {
     /// definition and not a concrete use of it.
     TyAdt(&'tcx AdtDef, &'tcx Substs<'tcx>),
 
+    TyForeign(DefId),
+
     /// The pointee of a string slice. Written as `str`.
     TyStr,
 
@@ -1117,13 +1119,6 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
-    pub fn is_structural(&self) -> bool {
-        match self.sty {
-            TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true,
-            _ => self.is_slice() | self.is_trait(),
-        }
-    }
-
     #[inline]
     pub fn is_simd(&self) -> bool {
         match self.sty {
@@ -1347,6 +1342,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         match self.sty {
             TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()),
             TyAdt(def, _) => Some(def.did),
+            TyForeign(did) => Some(did),
             TyClosure(id, _) => Some(id),
             _ => None,
         }
@@ -1396,6 +1392,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             TyRawPtr(_) |
             TyNever |
             TyTuple(..) |
+            TyForeign(..) |
             TyParam(_) |
             TyInfer(_) |
             TyError => {
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index c8037ce081a..39842a543b5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -553,7 +553,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         let result = match ty.sty {
             ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
-            ty::TyFloat(_) | ty::TyStr | ty::TyNever |
+            ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) |
             ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => {
                 // these types never have a destructor
                 Ok(ty::DtorckConstraint::empty())
@@ -714,6 +714,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
             TyAnon(def_id, _) |
             TyFnDef(def_id, _) => self.def_id(def_id),
             TyAdt(d, _) => self.def_id(d.did),
+            TyForeign(def_id) => self.def_id(def_id),
             TyFnPtr(f) => {
                 self.hash(f.unsafety());
                 self.hash(f.abi());
@@ -1109,6 +1110,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
         ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false,
 
+        // Foreign types can never have destructors
+        ty::TyForeign(..) => false,
+
         // Issue #22536: We first query type_moves_by_default.  It sees a
         // normalized version of the type, and therefore will definitely
         // know whether the type implements Copy (and thus needs no
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index df07844cceb..448ad4cf675 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -82,7 +82,8 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter<TypeWalkerArray<'tcx>> {
 fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
     match parent_ty.sty {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
-        ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
+        ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError |
+        ty::TyForeign(..) => {
         }
         ty::TyArray(ty, len) => {
             push_const(stack, len);
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 41e27fca3f3..c631e2c4db5 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -284,7 +284,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                 ty::TyError |
                 ty::TyStr |
                 ty::TyNever |
-                ty::TyParam(_) => {
+                ty::TyParam(_) |
+                ty::TyForeign(..) => {
                     // WfScalar, WfParameter, etc
                 }
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 0eb2c19fe44..acb929981fb 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -17,7 +17,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyAdt};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
 use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
-use ty::{TyClosure, TyGenerator, TyProjection, TyAnon};
+use ty::{TyClosure, TyGenerator, TyForeign, TyProjection, TyAnon};
 use ty::{TyDynamic, TyInt, TyUint, TyInfer};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use util::nodemap::FxHashSet;
@@ -1012,6 +1012,7 @@ define_print! {
                         Ok(())
                     }
                 }
+                TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
                 TyProjection(ref data) => data.print(f, cx),
                 TyAnon(def_id, substs) => {
                     ty::tls::with(|tcx| {
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 38461b0b364..8f08987505b 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -621,6 +621,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
+            ty::TyForeign(..) => FfiSafe,
+
             ty::TyParam(..) |
             ty::TyInfer(..) |
             ty::TyError |
@@ -723,6 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
                         hir::ForeignItemStatic(ref ty, _) => {
                             vis.check_foreign_static(ni.id, ty.span);
                         }
+                        hir::ForeignItemType => ()
                     }
                 }
             }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 65cf15e5a0e..909e01376b9 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -449,6 +449,7 @@ impl<'tcx> EntryKind<'tcx> {
             EntryKind::Enum(..) => Def::Enum(did),
             EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
             EntryKind::GlobalAsm => Def::GlobalAsm(did),
+            EntryKind::ForeignType => Def::TyForeign(did),
 
             EntryKind::ForeignMod |
             EntryKind::Impl(_) |
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 6b49be3e121..abe2b6d0c1b 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1419,6 +1419,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             }
             hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic,
             hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic,
+            hir::ForeignItemType => EntryKind::ForeignType,
         };
 
         Entry {
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index 43dbce5288a..3c3162bcb51 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -292,6 +292,7 @@ pub enum EntryKind<'tcx> {
     ForeignImmStatic,
     ForeignMutStatic,
     ForeignMod,
+    ForeignType,
     GlobalAsm,
     Type,
     Enum(ReprOptions),
@@ -325,6 +326,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for EntryKind<'gcx> {
             EntryKind::ForeignMutStatic |
             EntryKind::ForeignMod       |
             EntryKind::GlobalAsm        |
+            EntryKind::ForeignType      |
             EntryKind::Field |
             EntryKind::Type => {
                 // Nothing else to hash here.
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 14e33378969..e44f3f39824 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -288,7 +288,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     err.emit();
                 });
             }
-            ForeignItemKind::Static(..) => {}
+            ForeignItemKind::Static(..) | ForeignItemKind::Ty => {}
         }
 
         visit::walk_foreign_item(self, fi)
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 8abf7d3d09c..3beba03ee14 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -85,6 +85,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> {
         let ty_def_id = match self.tcx.type_of(item_def_id).sty {
             ty::TyAdt(adt, _) => adt.did,
+            ty::TyForeign(did) => did,
             ty::TyDynamic(ref obj, ..) if obj.principal().is_some() =>
                 obj.principal().unwrap().def_id(),
             ty::TyProjection(ref proj) => proj.trait_ref(self.tcx).def_id,
@@ -444,6 +445,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         let ty_def_id = match ty.sty {
             ty::TyAdt(adt, _) => Some(adt.did),
+            ty::TyForeign(did) => Some(did),
             ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
             ty::TyProjection(ref proj) => Some(proj.item_def_id),
             ty::TyFnDef(def_id, ..) |
@@ -800,7 +802,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
 impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         match ty.sty {
-            ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => {
+            ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) |
+            ty::TyFnDef(def_id, ..) |
+            ty::TyForeign(def_id) => {
                 if !self.item_is_accessible(def_id) {
                     let msg = format!("type `{}` is private", ty);
                     self.tcx.sess.span_err(self.span, &msg);
@@ -1329,6 +1333,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
         let ty_def_id = match ty.sty {
             ty::TyAdt(adt, _) => Some(adt.did),
+            ty::TyForeign(did) => Some(did),
             ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
             ty::TyProjection(ref proj) => {
                 if self.required_visibility == ty::Visibility::Invisible {
@@ -1349,8 +1354,13 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
         if let Some(def_id) = ty_def_id {
             // Non-local means public (private items can't leave their crate, modulo bugs)
             if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
-                let item = self.tcx.hir.expect_item(node_id);
-                let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
+                let vis = match self.tcx.hir.find(node_id) {
+                    Some(hir::map::NodeItem(item)) => &item.vis,
+                    Some(hir::map::NodeForeignItem(item)) => &item.vis,
+                    _ => bug!("expected item of foreign item"),
+                };
+
+                let vis = ty::Visibility::from_hir(vis, node_id, self.tcx);
 
                 if !vis.is_at_least(self.min_visibility, self.tcx) {
                     self.min_visibility = vis;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 7b1a602d849..880b370c7f6 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -419,17 +419,20 @@ impl<'a> Resolver<'a> {
 
     /// Constructs the reduced graph for one foreign item.
     fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) {
-        let def = match item.node {
+        let (def, ns) = match item.node {
             ForeignItemKind::Fn(..) => {
-                Def::Fn(self.definitions.local_def_id(item.id))
+                (Def::Fn(self.definitions.local_def_id(item.id)), ValueNS)
             }
             ForeignItemKind::Static(_, m) => {
-                Def::Static(self.definitions.local_def_id(item.id), m)
+                (Def::Static(self.definitions.local_def_id(item.id), m), ValueNS)
+            }
+            ForeignItemKind::Ty => {
+                (Def::TyForeign(self.definitions.local_def_id(item.id)), TypeNS)
             }
         };
         let parent = self.current_module;
         let vis = self.resolve_visibility(&item.vis);
-        self.define(parent, item.ident, ValueNS, (def, vis, item.span, expansion));
+        self.define(parent, item.ident, ns, (def, vis, item.span, expansion));
     }
 
     fn build_reduced_graph_for_block(&mut self, block: &Block, expansion: Mark) {
@@ -462,7 +465,7 @@ impl<'a> Resolver<'a> {
                                              span);
                 self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
             }
-            Def::Variant(..) | Def::TyAlias(..) => {
+            Def::Variant(..) | Def::TyAlias(..) | Def::TyForeign(..) => {
                 self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
             }
             Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 8d8e6105e47..83eeaf551c5 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -468,7 +468,8 @@ impl<'a> PathSource<'a> {
             PathSource::Type => match def {
                 Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
                 Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
-                Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) => true,
+                Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) |
+                Def::TyForeign(..) => true,
                 _ => false,
             },
             PathSource::Trait => match def {
@@ -707,6 +708,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                 HasTypeParameters(generics, ItemRibKind)
             }
             ForeignItemKind::Static(..) => NoTypeParameters,
+            ForeignItemKind::Ty => NoTypeParameters,
         };
         self.with_type_parameter_rib(type_parameters, |this| {
             visit::walk_foreign_item(this, foreign_item);
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index ca44a088e23..4eac4398c18 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -263,6 +263,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             HirDef::Union(..) |
             HirDef::Enum(..) |
             HirDef::TyAlias(..) |
+            HirDef::TyForeign(..) |
             HirDef::Trait(_) => {
                 let span = self.span_from_span(sub_span.expect("No span found for type ref"));
                 self.dumper.dump_ref(Ref {
@@ -1539,6 +1540,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
 
                 self.visit_ty(ty);
             }
+            ast::ForeignItemKind::Ty => {
+                if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
+                    down_cast_data!(var_data, DefData, item.span);
+                    self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data);
+                }
+            }
         }
     }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 1c6007966af..cf2cad1b38c 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -173,6 +173,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
+            // FIXME(plietar): needs a new DefKind in rls-data
+            ast::ForeignItemKind::Ty => None,
         }
     }
 
@@ -642,6 +644,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             HirDef::Union(def_id) |
             HirDef::Enum(def_id) |
             HirDef::TyAlias(def_id) |
+            HirDef::TyForeign(def_id) |
             HirDef::AssociatedTy(def_id) |
             HirDef::Trait(def_id) |
             HirDef::TyParam(def_id) => {
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 88f574d513b..b0844d1b824 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -808,6 +808,23 @@ impl Sig for ast::ForeignItem {
 
                 Ok(extend_sig(ty_sig, text, defs, vec![]))
             }
+            ast::ForeignItemKind::Ty => {
+                let mut text = "type ".to_owned();
+                let name = self.ident.to_string();
+                let defs = vec![SigElement {
+                    id: id_from_node_id(self.id, scx),
+                    start: offset + text.len(),
+                    end: offset + text.len() + name.len(),
+                }];
+                text.push_str(&name);
+                text.push(';');
+
+                Ok(Signature {
+                    text: text,
+                    defs: defs,
+                    refs: vec![],
+                })
+            }
         }
     }
 }
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 6fd24c1786c..9df057c77a9 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -32,6 +32,7 @@ use rustc::session::Session;
 use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::FxHashMap;
+use rustc_trans_utils;
 
 use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
@@ -301,6 +302,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         common::type_is_freeze(self.tcx, ty)
     }
 
+    pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
+        rustc_trans_utils::common::type_has_metadata(self.tcx, ty)
+    }
+
     pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> {
         self.tcx
     }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 3bde78e2c6a..4f07af9071d 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -543,6 +543,11 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                         trait_pointer_metadata(cx, t, None, unique_type_id),
             false)
         }
+        ty::TyForeign(..) => {
+            MetadataCreationResult::new(
+                        foreign_type_metadata(cx, t, unique_type_id),
+            false)
+        }
         ty::TyRawPtr(ty::TypeAndMut{ty, ..}) |
         ty::TyRef(_, ty::TypeAndMut{ty, ..}) => {
             match ptr_metadata(ty) {
@@ -752,6 +757,17 @@ fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     return ty_metadata;
 }
 
+fn foreign_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                                   t: Ty<'tcx>,
+                                   unique_type_id: UniqueTypeId) -> DIType {
+    debug!("foreign_type_metadata: {:?}", t);
+
+    let llvm_type = type_of::type_of(cx, t);
+
+    let name = compute_debuginfo_type_name(cx, t, false);
+    create_struct_stub(cx, llvm_type, &name, unique_type_id, NO_SCOPE_METADATA)
+}
+
 fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                    pointer_type: Ty<'tcx>,
                                    pointee_type_metadata: DIType)
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 7bf9d39ea2f..85467f5bfbd 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -48,6 +48,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()),
         ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()),
         ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()),
+        ty::TyForeign(def_id) => push_item_name(cx, def_id, qualified, output),
         ty::TyAdt(def, substs) => {
             push_item_name(cx, def.did, qualified, output);
             push_type_params(cx, substs, output);
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index f78d80a197c..e8023917568 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -139,13 +139,15 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         }
         "size_of_val" => {
             let tp_ty = substs.type_at(0);
-            if !bcx.ccx.shared().type_is_sized(tp_ty) {
+            if bcx.ccx.shared().type_is_sized(tp_ty) {
+                let lltp_ty = type_of::type_of(ccx, tp_ty);
+                C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
+            } else if bcx.ccx.shared().type_has_metadata(tp_ty) {
                 let (llsize, _) =
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llsize
             } else {
-                let lltp_ty = type_of::type_of(ccx, tp_ty);
-                C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
+                C_usize(ccx, 0u64)
             }
         }
         "min_align_of" => {
@@ -154,12 +156,14 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
         }
         "min_align_of_val" => {
             let tp_ty = substs.type_at(0);
-            if !bcx.ccx.shared().type_is_sized(tp_ty) {
+            if bcx.ccx.shared().type_is_sized(tp_ty) {
+                C_usize(ccx, ccx.align_of(tp_ty) as u64)
+            } else if bcx.ccx.shared().type_has_metadata(tp_ty) {
                 let (_, llalign) =
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
-                C_usize(ccx, ccx.align_of(tp_ty) as u64)
+                C_usize(ccx, 1u64)
             }
         }
         "pref_align_of" => {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 1b8e68f691a..cea7b9585d8 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -428,11 +428,11 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     .projection_ty(tcx, &projection.elem);
                 let base = tr_base.to_const(span);
                 let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
-                let is_sized = self.ccx.shared().type_is_sized(projected_ty);
+                let has_metadata = self.ccx.shared().type_has_metadata(projected_ty);
 
                 let (projected, llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => {
-                        let (base, extra) = if is_sized {
+                        let (base, extra) = if !has_metadata {
                             (base.llval, ptr::null_mut())
                         } else {
                             base.get_fat_ptr()
@@ -463,7 +463,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                     mir::ProjectionElem::Field(ref field, _) => {
                         let llprojected = adt::const_get_field(self.ccx, tr_base.ty, base.llval,
                                                                field.index());
-                        let llextra = if is_sized {
+                        let llextra = if !has_metadata {
                             ptr::null_mut()
                         } else {
                             tr_base.llextra
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index 6799e52904d..d939acaccd9 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -147,15 +147,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
         //   * Packed struct - There is no alignment padding
         //   * Field is sized - pointer is properly aligned already
         if st.offsets[ix] == layout::Size::from_bytes(0) || st.packed ||
-            bcx.ccx.shared().type_is_sized(fty) {
-                return (bcx.struct_gep(
-                        ptr_val, adt::struct_llfields_index(st, ix)), alignment);
-            }
+            bcx.ccx.shared().type_is_sized(fty)
+        {
+            return (bcx.struct_gep(
+                    ptr_val, adt::struct_llfields_index(st, ix)), alignment);
+        }
 
-        // If the type of the last field is [T] or str, then we don't need to do
+        // If the type of the last field is [T], str or a foreign type, then we don't need to do
         // any adjusments
         match fty.sty {
-            ty::TySlice(..) | ty::TyStr => {
+            ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => {
                 return (bcx.struct_gep(
                         ptr_val, adt::struct_llfields_index(st, ix)), alignment);
             }
@@ -328,7 +329,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 let ((llprojected, align), llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => bug!(),
                     mir::ProjectionElem::Field(ref field, _) => {
-                        let llextra = if self.ccx.shared().type_is_sized(projected_ty.to_ty(tcx)) {
+                        let has_metadata = self.ccx.shared()
+                            .type_has_metadata(projected_ty.to_ty(tcx));
+                        let llextra = if !has_metadata {
                             ptr::null_mut()
                         } else {
                             tr_base.llextra
@@ -415,3 +418,4 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         self.monomorphize(&lvalue_ty.to_ty(tcx))
     }
 }
+
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 822431eba42..777b86387e8 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -364,7 +364,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
                 // Note: lvalues are indirect, so storing the `llval` into the
                 // destination effectively creates a reference.
-                let operand = if bcx.ccx.shared().type_is_sized(ty) {
+                let operand = if !bcx.ccx.shared().type_has_metadata(ty) {
                     OperandRef {
                         val: OperandValue::Immediate(tr_lvalue.llval),
                         ty: ref_ty,
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index db1af8cdefb..fb68be293a7 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -230,4 +230,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     ccx.instances().borrow_mut().insert(instance, lldecl);
 }
-
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 992c74b9020..cac09a81361 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -22,7 +22,7 @@ use syntax::ast;
 pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
     match ty.sty {
         ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
-        ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => {
+        ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if ccx.shared().type_has_metadata(t) => {
             in_memory_type_of(ccx, t).ptr_to()
         }
         ty::TyAdt(def, _) if def.is_box() => {
@@ -62,7 +62,7 @@ pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 /// is too large for it to be placed in SSA value (by our rules).
 /// For the raw type without far pointer indirection, see `in_memory_type_of`.
 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
-    let ty = if !cx.shared().type_is_sized(ty) {
+    let ty = if cx.shared().type_has_metadata(ty) {
         cx.tcx().mk_imm_ptr(ty)
     } else {
         ty
@@ -106,7 +106,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
     }
 
     let ptr_ty = |ty: Ty<'tcx>| {
-        if !cx.shared().type_is_sized(ty) {
+        if cx.shared().type_has_metadata(ty) {
             if let ty::TyStr = ty.sty {
                 // This means we get a nicer name in the output (str is always
                 // unsized).
@@ -158,7 +158,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       // fat pointers is of the right type (e.g. for array accesses), even
       // when taking the address of an unsized field in a struct.
       ty::TySlice(ty) => in_memory_type_of(cx, ty),
-      ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
+      ty::TyStr | ty::TyDynamic(..) | ty::TyForeign(..) => Type::i8(cx),
 
       ty::TyFnDef(..) => Type::nil(cx),
       ty::TyFnPtr(sig) => {
diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs
index c87d86262ef..cf9b80e5ed4 100644
--- a/src/librustc_trans_utils/collector.rs
+++ b/src/librustc_trans_utils/collector.rs
@@ -203,7 +203,7 @@ use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::mir::{self, Location};
 use rustc::mir::visit::Visitor as MirVisitor;
 
-use common::{def_ty, instance_ty, type_is_sized};
+use common::{def_ty, instance_ty, type_has_metadata};
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 
@@ -782,7 +782,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             target_ty: Ty<'tcx>)
                                             -> (Ty<'tcx>, Ty<'tcx>) {
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
-        if !type_is_sized(tcx, inner_source) {
+        if type_has_metadata(tcx, inner_source) {
             (inner_source, inner_target)
         } else {
             tcx.struct_lockstep_tails(inner_source, inner_target)
diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs
index 634e37220e2..ec9c5b1119b 100644
--- a/src/librustc_trans_utils/common.rs
+++ b/src/librustc_trans_utils/common.rs
@@ -25,6 +25,19 @@ pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> boo
     ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
 }
 
+pub fn type_has_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    if type_is_sized(tcx, ty) {
+        return false;
+    }
+
+    let tail = tcx.struct_tail(ty);
+    match tail.sty {
+        ty::TyForeign(..) => false,
+        ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true,
+        _ => bug!("unexpected unsized tail: {:?}", tail.sty),
+    }
+}
+
 pub fn requests_inline<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: &ty::Instance<'tcx>
diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs
index b468c510c09..6a341a1e7d3 100644
--- a/src/librustc_trans_utils/lib.rs
+++ b/src/librustc_trans_utils/lib.rs
@@ -48,7 +48,7 @@ use rustc::util::nodemap::NodeSet;
 
 use syntax::attr;
 
-mod common;
+pub mod common;
 pub mod link;
 pub mod collector;
 pub mod trans_item;
diff --git a/src/librustc_trans_utils/trans_item.rs b/src/librustc_trans_utils/trans_item.rs
index 0ada39d7d27..817ceefeb7f 100644
--- a/src/librustc_trans_utils/trans_item.rs
+++ b/src/librustc_trans_utils/trans_item.rs
@@ -335,6 +335,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                         output);
                 }
             },
+            ty::TyForeign(did) => self.push_def_path(did, output),
             ty::TyFnDef(..) |
             ty::TyFnPtr(_) => {
                 let sig = t.fn_sig(self.tcx);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 7c9497badfb..c7f7e62fd61 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -928,7 +928,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let span = path.span;
         match path.def {
-            Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
+            Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) |
+            Def::Union(did) | Def::TyForeign(did) => {
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_type_params(path.segments.split_last().unwrap().1);
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 9c6cacb9d25..7b35b466830 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -13,7 +13,7 @@
 //! A cast `e as U` is valid if one of the following holds:
 //! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
 //! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
-//!    unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
+//!    pointer_kind(`T`) = pointer_kind(`U_0`); *ptr-ptr-cast*
 //! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
 //! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
 //! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
@@ -26,7 +26,7 @@
 //! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
 //!
 //! where `&.T` and `*T` are references of either mutability,
-//! and where unsize_kind(`T`) is the kind of the unsize info
+//! and where pointer_kind(`T`) is the kind of the unsize info
 //! in `T` - the vtable for a trait definition (e.g. `fmt::Display` or
 //! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`).
 //!
@@ -64,11 +64,16 @@ pub struct CastCheck<'tcx> {
     span: Span,
 }
 
-/// The kind of the unsize info (length or vtable) - we only allow casts between
-/// fat pointers if their unsize-infos have the same kind.
+/// The kind of pointer and associated metadata (thin, length or vtable) - we
+/// only allow casts between fat pointers if their metadata have the same
+/// kind.
 #[derive(Copy, Clone, PartialEq, Eq)]
-enum UnsizeKind<'tcx> {
+enum PointerKind<'tcx> {
+    /// No metadata attached, ie pointer to sized type or foreign type
+    Thin,
+    /// A trait object
     Vtable(Option<DefId>),
+    /// Slice
     Length,
     /// The unsize info of this projection
     OfProjection(&'tcx ty::ProjectionTy<'tcx>),
@@ -79,22 +84,28 @@ enum UnsizeKind<'tcx> {
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// Returns the kind of unsize information of t, or None
     /// if t is sized or it is unknown.
-    fn unsize_kind(&self, t: Ty<'tcx>) -> Option<UnsizeKind<'tcx>> {
+    fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> {
+        if self.type_is_known_to_be_sized(t, span) {
+            return PointerKind::Thin;
+        }
+
         match t.sty {
-            ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
+            ty::TySlice(_) | ty::TyStr => PointerKind::Length,
             ty::TyDynamic(ref tty, ..) =>
-                Some(UnsizeKind::Vtable(tty.principal().map(|p| p.def_id()))),
+                PointerKind::Vtable(tty.principal().map(|p| p.def_id())),
             ty::TyAdt(def, substs) if def.is_struct() => {
                 // FIXME(arielb1): do some kind of normalization
                 match def.struct_variant().fields.last() {
-                    None => None,
-                    Some(f) => self.unsize_kind(f.ty(self.tcx, substs)),
+                    None => PointerKind::Thin,
+                    Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span),
                 }
             }
+            // Pointers to foreign types are thin, despite being unsized
+            ty::TyForeign(..) => PointerKind::Thin,
             // We should really try to normalize here.
-            ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
-            ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
-            _ => None,
+            ty::TyProjection(ref pi) => PointerKind::OfProjection(pi),
+            ty::TyParam(ref p) => PointerKind::OfParam(p),
+            _ => panic!(),
         }
     }
 }
@@ -446,20 +457,23 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
         // ptr-ptr cast. vtables must match.
 
-        // Cast to sized is OK
-        if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+        // Cast to thin pointer is OK
+        let cast_kind = fcx.pointer_kind(m_cast.ty, self.span);
+        if cast_kind == PointerKind::Thin {
             return Ok(CastKind::PtrPtrCast);
         }
 
-        // sized -> unsized? report invalid cast (don't complain about vtable kinds)
-        if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
+        // thin -> fat? report invalid cast (don't complain about vtable kinds)
+        let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
+        if expr_kind == PointerKind::Thin {
             return Err(CastError::SizedUnsizedCast);
         }
 
         // vtable kinds must match
-        match (fcx.unsize_kind(m_cast.ty), fcx.unsize_kind(m_expr.ty)) {
-            (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
-            _ => Err(CastError::DifferingKinds),
+        if cast_kind == expr_kind {
+            Ok(CastKind::PtrPtrCast)
+        } else {
+            Err(CastError::DifferingKinds)
         }
     }
 
@@ -467,9 +481,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            fcx: &FnCtxt<'a, 'gcx, 'tcx>,
                            m_cast: &'tcx ty::TypeAndMut<'tcx>)
                            -> Result<CastKind, CastError> {
-        // fptr-ptr cast. must be to sized ptr
+        // fptr-ptr cast. must be to thin ptr
 
-        if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+        if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
             Ok(CastKind::FnPtrPtrCast)
         } else {
             Err(CastError::IllegalCast)
@@ -480,9 +494,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            fcx: &FnCtxt<'a, 'gcx, 'tcx>,
                            m_expr: &'tcx ty::TypeAndMut<'tcx>)
                            -> Result<CastKind, CastError> {
-        // ptr-addr cast. must be from sized ptr
+        // ptr-addr cast. must be from thin ptr
 
-        if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
+        if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin {
             Ok(CastKind::PtrAddrCast)
         } else {
             Err(CastError::NeedViaThinPtr)
@@ -519,7 +533,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            m_cast: &'tcx ty::TypeAndMut<'tcx>)
                            -> Result<CastKind, CastError> {
         // ptr-addr cast. pointer must be thin.
-        if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+        if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
             Ok(CastKind::AddrPtrCast)
         } else {
             Err(CastError::IllegalCast)
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 78941cb3a56..a24f420af80 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -414,6 +414,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
             ty::TyAdt(def, _) => {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
             }
+            ty::TyForeign(did) => {
+                self.assemble_inherent_impl_candidates_for_type(did);
+            }
             ty::TyParam(p) => {
                 self.assemble_inherent_candidates_from_param(self_ty, p);
             }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 23148406a11..8613ec86b4a 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -451,6 +451,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         fn is_local(ty: Ty) -> bool {
             match ty.sty {
                 ty::TyAdt(def, _) => def.did.is_local(),
+                ty::TyForeign(did) => did.is_local(),
 
                 ty::TyDynamic(ref tr, ..) => tr.principal()
                     .map_or(false, |p| p.def_id().is_local()),
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index 15e15abfb36..c56a3b91ca3 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -117,6 +117,9 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
             ty::TyAdt(def, _) => {
                 self.check_def_id(item, def.did);
             }
+            ty::TyForeign(did) => {
+                self.check_def_id(item, did);
+            }
             ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
                 self.check_def_id(item, data.principal().unwrap().def_id());
             }
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 097720adad4..a5edc95b79b 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -68,10 +68,10 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                 }
 
                 // In addition to the above rules, we restrict impls of defaulted traits
-                // so that they can only be implemented on structs/enums. To see why this
-                // restriction exists, consider the following example (#22978). Imagine
-                // that crate A defines a defaulted trait `Foo` and a fn that operates
-                // on pairs of types:
+                // so that they can only be implemented on nominal types, such as structs,
+                // enums or foreign types. To see why this restriction exists, consider the
+                // following example (#22978). Imagine that crate A defines a defaulted trait
+                // `Foo` and a fn that operates on pairs of types:
                 //
                 // ```
                 // // Crate A
@@ -109,11 +109,12 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                     let self_ty = trait_ref.self_ty();
                     let opt_self_def_id = match self_ty.sty {
                         ty::TyAdt(self_def, _) => Some(self_def.did),
+                        ty::TyForeign(did) => Some(did),
                         _ => None,
                     };
 
                     let msg = match opt_self_def_id {
-                        // We only want to permit structs/enums, but not *all* structs/enums.
+                        // We only want to permit nominal types, but not *all* nominal types.
                         // They must be local to the current crate, so that people
                         // can't do `unsafe impl Send for Rc<SomethingLocal>` or
                         // `impl !Send for Box<SomethingLocalAndSend>`.
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 68ba1b4c44c..75e864d07a6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -916,7 +916,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         NodeForeignItem(item) => {
             match item.node {
                 ForeignItemStatic(..) => &no_generics,
-                ForeignItemFn(_, _, ref generics) => generics
+                ForeignItemFn(_, _, ref generics) => generics,
+                ForeignItemType => &no_generics,
             }
         }
 
@@ -1094,7 +1095,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     let substs = Substs::identity_for_item(tcx, def_id);
                     tcx.mk_fn_def(def_id, substs)
                 }
-                ForeignItemStatic(ref t, _) => icx.to_ty(t)
+                ForeignItemStatic(ref t, _) => icx.to_ty(t),
+                ForeignItemType => tcx.mk_foreign(def_id),
             }
         }
 
@@ -1363,7 +1365,8 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         NodeForeignItem(item) => {
             match item.node {
                 ForeignItemStatic(..) => &no_generics,
-                ForeignItemFn(_, _, ref generics) => generics
+                ForeignItemFn(_, _, ref generics) => generics,
+                ForeignItemType => &no_generics,
             }
         }
 
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 857b35158f2..ef6552c8e33 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -305,7 +305,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
         match ty.sty {
             ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
-            ty::TyStr | ty::TyNever => {
+            ty::TyStr | ty::TyNever | ty::TyForeign(..) => {
                 // leaf type -- noop
             }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4e8bf5f9109..f8fea643d5e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -419,6 +419,8 @@ pub enum ItemEnum {
     ForeignFunctionItem(Function),
     /// `static`s from an extern block
     ForeignStaticItem(Static),
+    /// `type`s from an extern block
+    ForeignTypeItem,
     MacroItem(Macro),
     PrimitiveItem(PrimitiveType),
     AssociatedConstItem(Type, Option<String>),
@@ -1646,6 +1648,7 @@ pub enum TypeKind {
     Trait,
     Variant,
     Typedef,
+    Foreign,
 }
 
 pub trait GetDefId {
@@ -2027,6 +2030,17 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     is_generic: false,
                 }
             }
+            ty::TyForeign(did) => {
+                inline::record_extern_fqn(cx, did, TypeKind::Foreign);
+                let path = external_path(cx, &cx.tcx.item_name(did),
+                                         None, false, vec![], Substs::empty());
+                ResolvedPath {
+                    path: path,
+                    typarams: None,
+                    did: did,
+                    is_generic: false,
+                }
+            }
             ty::TyDynamic(ref obj, ref reg) => {
                 if let Some(principal) = obj.principal() {
                     let did = principal.def_id();
@@ -2840,6 +2854,9 @@ impl Clean<Item> for hir::ForeignItem {
                     expr: "".to_string(),
                 })
             }
+            hir::ForeignItemType => {
+                ForeignTypeItem
+            }
         };
         Item {
             name: Some(self.name.clean(cx)),
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index f584c4e2f4d..c9c5f01f0ae 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -41,6 +41,7 @@ pub enum ItemType {
     Constant        = 17,
     AssociatedConst = 18,
     Union           = 19,
+    ForeignType     = 20,
 }
 
 
@@ -82,6 +83,7 @@ impl<'a> From<&'a clean::Item> for ItemType {
             clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
             clean::AssociatedTypeItem(..)  => ItemType::AssociatedType,
             clean::DefaultImplItem(..)     => ItemType::Impl,
+            clean::ForeignTypeItem         => ItemType::ForeignType,
             clean::StrippedItem(..)        => unreachable!(),
         }
     }
@@ -100,6 +102,7 @@ impl From<clean::TypeKind> for ItemType {
             clean::TypeKind::Const    => ItemType::Constant,
             clean::TypeKind::Variant  => ItemType::Variant,
             clean::TypeKind::Typedef  => ItemType::Typedef,
+            clean::TypeKind::Foreign  => ItemType::ForeignType,
         }
     }
 }
@@ -127,6 +130,7 @@ impl ItemType {
             ItemType::AssociatedType  => "associatedtype",
             ItemType::Constant        => "constant",
             ItemType::AssociatedConst => "associatedconstant",
+            ItemType::ForeignType     => "foreigntype",
         }
     }
 
@@ -139,7 +143,8 @@ impl ItemType {
             ItemType::Typedef |
             ItemType::Trait |
             ItemType::Primitive |
-            ItemType::AssociatedType => NameSpace::Type,
+            ItemType::AssociatedType |
+            ItemType::ForeignType => NameSpace::Type,
 
             ItemType::ExternCrate |
             ItemType::Import |
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index d538428a7e9..ac2cb1665a7 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2044,6 +2044,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                 ItemType::Primitive       => ("primitives", "Primitive Types"),
                 ItemType::AssociatedType  => ("associated-types", "Associated Types"),
                 ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+                ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
             };
             write!(w, "<h2 id='{id}' class='section-header'>\
                        <a href=\"#{id}\">{name}</a></h2>\n<table>",
@@ -3679,7 +3680,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
                    ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
                    ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
                    ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
-                   ItemType::AssociatedType, ItemType::AssociatedConst] {
+                   ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
         if items.iter().any(|it| {
             if let clean::DefaultImplItem(..) = it.inner {
                 false
@@ -3708,6 +3709,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item,
                 ItemType::Primitive       => ("primitives", "Primitive Types"),
                 ItemType::AssociatedType  => ("associated-types", "Associated Types"),
                 ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+                ItemType::ForeignType     => ("foreign-types", "Foreign Types"),
             };
             sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
                                       id = short,
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 146629486fa..959543404d8 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -90,7 +90,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             clean::VariantItem(..) | clean::MethodItem(..) |
             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
             clean::ConstantItem(..) | clean::UnionItem(..) |
-            clean::AssociatedConstItem(..) => {
+            clean::AssociatedConstItem(..) | clean::ForeignTypeItem => {
                 if i.def_id.is_local() {
                     if !self.access_levels.is_exported(i.def_id) {
                         return None;
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index c19ece6a314..35c33f40253 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -10,25 +10,66 @@
 
 //! A module for working with processes.
 //!
-//! # Examples
+//! This module is mostly concerned with spawning and interacting with child
+//! processes, but it also provides [`abort`] and [`exit`] for terminating the
+//! current process.
 //!
-//! Basic usage where we try to execute the `cat` shell command:
+//! # Spawning a process
 //!
-//! ```should_panic
+//! The [`Command`] struct is used to configure and spawn processes:
+//!
+//! ```
 //! use std::process::Command;
 //!
-//! let mut child = Command::new("/bin/cat")
-//!                         .arg("file.txt")
-//!                         .spawn()
-//!                         .expect("failed to execute child");
+//! let output = Command::new("echo")
+//!                      .arg("Hello world")
+//!                      .output()
+//!                      .expect("Failed to execute command");
+//!
+//! assert_eq!(b"Hello world\n", output.stdout.as_slice());
+//! ```
+//!
+//! Several methods on [`Command`], such as [`spawn`] or [`output`], can be used
+//! to spawn a process. In particular, [`output`] spawns the child process and
+//! waits until the process terminates, while [`spawn`] will return a [`Child`]
+//! that represents the spawned child process.
+//!
+//! # Handling I/O
+//!
+//! The [`stdout`], [`stdin`], and [`stderr`] of a child process can be
+//! configured by passing an [`Stdio`] to the corresponding method on
+//! [`Command`]. Once spawned, they can be accessed from the [`Child`]. For
+//! example, piping output from one command into another command can be done
+//! like so:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
 //!
-//! let ecode = child.wait()
-//!                  .expect("failed to wait on child");
+//! // stdout must be configured with `Stdio::piped` in order to use
+//! // `echo_child.stdout`
+//! let echo_child = Command::new("echo")
+//!     .arg("Oh no, a tpyo!")
+//!     .stdout(Stdio::piped())
+//!     .spawn()
+//!     .expect("Failed to start echo process");
+//!
+//! // Note that `echo_child` is moved here, but we won't be needing
+//! // `echo_child` anymore
+//! let echo_out = echo_child.stdout.expect("Failed to open echo stdout");
+//!
+//! let mut sed_child = Command::new("sed")
+//!     .arg("s/tpyo/typo/")
+//!     .stdin(Stdio::from(echo_out))
+//!     .stdout(Stdio::piped())
+//!     .spawn()
+//!     .expect("Failed to start sed process");
 //!
-//! assert!(ecode.success());
+//! let output = sed_child.wait_with_output().expect("Failed to wait on sed");
+//! assert_eq!(b"Oh no, a typo!\n", output.stdout.as_slice());
 //! ```
 //!
-//! Calling a command with input and reading its output:
+//! Note that [`ChildStderr`] and [`ChildStdout`] implement [`Write`] and
+//! [`ChildStdin`] implements [`Read`]:
 //!
 //! ```no_run
 //! use std::process::{Command, Stdio};
@@ -52,6 +93,26 @@
 //!
 //! assert_eq!(b"test", output.stdout.as_slice());
 //! ```
+//!
+//! [`abort`]: fn.abort.html
+//! [`exit`]: fn.exit.html
+//!
+//! [`Command`]: struct.Command.html
+//! [`spawn`]: struct.Command.html#method.spawn
+//! [`output`]: struct.Command.html#method.output
+//!
+//! [`Child`]: struct.Child.html
+//! [`ChildStdin`]: struct.ChildStdin.html
+//! [`ChildStdout`]: struct.ChildStdout.html
+//! [`ChildStderr`]: struct.ChildStderr.html
+//! [`Stdio`]: struct.Stdio.html
+//!
+//! [`stdout`]: struct.Command.html#method.stdout
+//! [`stdin`]: struct.Command.html#method.stdin
+//! [`stderr`]: struct.Command.html#method.stderr
+//!
+//! [`Write`]: ../io/trait.Write.html
+//! [`Read`]: ../io/trait.Read.html
 
 #![stable(feature = "process", since = "1.0.0")]
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 090fc193b38..d3995d95792 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2007,13 +2007,16 @@ pub enum ForeignItemKind {
     /// A foreign static item (`static ext: u8`), with optional mutability
     /// (the boolean is true when mutable)
     Static(P<Ty>, bool),
+    /// A foreign type
+    Ty,
 }
 
 impl ForeignItemKind {
     pub fn descriptive_variant(&self) -> &str {
         match *self {
             ForeignItemKind::Fn(..) => "foreign function",
-            ForeignItemKind::Static(..) => "foreign static item"
+            ForeignItemKind::Static(..) => "foreign static item",
+            ForeignItemKind::Ty => "foreign type",
         }
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 02aba8a3612..30451ec757a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -404,6 +404,9 @@ declare_features! (
 
     // `crate` as visibility modifier, synonymous to `pub(crate)`
     (active, crate_visibility_modifier, "1.23.0", Some(45388)),
+
+    // extern types
+    (active, extern_types, "1.23.0", Some(43467)),
 );
 
 declare_features! (
@@ -1398,13 +1401,23 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     }
 
     fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
-        let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs, "link_name") {
-            Some(val) => val.as_str().starts_with("llvm."),
-            _ => false
-        };
-        if links_to_llvm {
-            gate_feature_post!(&self, link_llvm_intrinsics, i.span,
-                              "linking to LLVM intrinsics is experimental");
+        match i.node {
+            ast::ForeignItemKind::Fn(..) |
+            ast::ForeignItemKind::Static(..) => {
+                let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name");
+                let links_to_llvm = match link_name {
+                    Some(val) => val.as_str().starts_with("llvm."),
+                    _ => false
+                };
+                if links_to_llvm {
+                    gate_feature_post!(&self, link_llvm_intrinsics, i.span,
+                                       "linking to LLVM intrinsics is experimental");
+                }
+            }
+            ast::ForeignItemKind::Ty => {
+                    gate_feature_post!(&self, extern_types, i.span,
+                                       "extern types are experimental");
+            }
         }
 
         visit::walk_foreign_item(self, i)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 518386a2ad2..fea49424dc8 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1069,6 +1069,7 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: ForeignItem, folder: &mut T) -> For
             ForeignItemKind::Static(t, m) => {
                 ForeignItemKind::Static(folder.fold_ty(t), m)
             }
+            ForeignItemKind::Ty => ForeignItemKind::Ty,
         },
         span: folder.new_span(ni.span)
     }
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index db49ab10343..b8151819bff 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -153,17 +153,15 @@ impl Diagnostic {
     fn from_diagnostic_builder(db: &DiagnosticBuilder,
                                je: &JsonEmitter)
                                -> Diagnostic {
-        let sugg = db.suggestions.iter().flat_map(|sugg| {
-            je.render(sugg).into_iter().map(move |rendered| {
-                Diagnostic {
-                    message: sugg.msg.clone(),
-                    code: None,
-                    level: "help",
-                    spans: DiagnosticSpan::from_suggestion(sugg, je),
-                    children: vec![],
-                    rendered: Some(rendered),
-                }
-            })
+        let sugg = db.suggestions.iter().map(|sugg| {
+            Diagnostic {
+                message: sugg.msg.clone(),
+                code: None,
+                level: "help",
+                spans: DiagnosticSpan::from_suggestion(sugg, je),
+                children: vec![],
+                rendered: None,
+            }
         });
         Diagnostic {
             message: db.message(),
@@ -356,9 +354,3 @@ impl DiagnosticCode {
         })
     }
 }
-
-impl JsonEmitter {
-    fn render(&self, suggestion: &CodeSuggestion) -> Vec<String> {
-        suggestion.splice_lines(&*self.cm).iter().map(|line| line.0.to_owned()).collect()
-    }
-}
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e96a5417aff..a3a265450ab 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5687,6 +5687,24 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parse a type from a foreign module
+    fn parse_item_foreign_type(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>)
+                             -> PResult<'a, ForeignItem> {
+        self.expect_keyword(keywords::Type)?;
+
+        let ident = self.parse_ident()?;
+        let hi = self.span;
+        self.expect(&token::Semi)?;
+        Ok(ast::ForeignItem {
+            ident: ident,
+            attrs: attrs,
+            node: ForeignItemKind::Ty,
+            id: ast::DUMMY_NODE_ID,
+            span: lo.to(hi),
+            vis: vis
+        })
+    }
+
     /// Parse extern crate links
     ///
     /// # Examples
@@ -6161,6 +6179,10 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Fn) {
             return Ok(Some(self.parse_item_foreign_fn(visibility, lo, attrs)?));
         }
+        // FOREIGN TYPE ITEM
+        if self.check_keyword(keywords::Type) {
+            return Ok(Some(self.parse_item_foreign_type(visibility, lo, attrs)?));
+        }
 
         // FIXME #5668: this will occur for a macro invocation:
         match self.parse_macro_use_or_failure(attrs, true, false, lo, visibility)? {
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 656a51c6637..8a970fd4098 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1112,6 +1112,13 @@ impl<'a> State<'a> {
                 self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
             }
+            ast::ForeignItemKind::Ty => {
+                self.head(&visibility_qualified(&item.vis, "type"))?;
+                self.print_ident(item.ident)?;
+                self.s.word(";")?;
+                self.end()?; // end the head-ibox
+                self.end() // end the outer cbox
+            }
         }
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 4198055f670..96e47a6cc0f 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -477,6 +477,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a
             visitor.visit_generics(generics)
         }
         ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
+        ForeignItemKind::Ty => (),
     }
 
     walk_list!(visitor, visit_attribute, &foreign_item.attrs);
diff --git a/src/test/compile-fail/extern-types-distinct-types.rs b/src/test/compile-fail/extern-types-distinct-types.rs
new file mode 100644
index 00000000000..8b434bbfc6d
--- /dev/null
+++ b/src/test/compile-fail/extern-types-distinct-types.rs
@@ -0,0 +1,22 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+    type B;
+}
+
+fn foo(r: &A) -> &B {
+    r //~ ERROR mismatched types
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs
new file mode 100644
index 00000000000..2f00cf812e4
--- /dev/null
+++ b/src/test/compile-fail/extern-types-not-sync-send.rs
@@ -0,0 +1,28 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure extern types are !Sync and !Send.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+fn assert_sync<T: ?Sized + Sync>() { }
+fn assert_send<T: ?Sized + Send>() { }
+
+fn main() {
+    assert_sync::<A>();
+    //~^ ERROR the trait bound `A: std::marker::Sync` is not satisfied
+
+    assert_send::<A>();
+    //~^ ERROR the trait bound `A: std::marker::Send` is not satisfied
+}
diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs
new file mode 100644
index 00000000000..faa27894806
--- /dev/null
+++ b/src/test/compile-fail/extern-types-unsized.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure extern types are !Sized.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+struct Foo {
+    x: u8,
+    tail: A,
+}
+
+struct Bar<T: ?Sized> {
+    x: u8,
+    tail: T,
+}
+
+fn assert_sized<T>() { }
+
+fn main() {
+    assert_sized::<A>();
+    //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
+
+    assert_sized::<Foo>();
+    //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
+
+    assert_sized::<Bar<A>>();
+    //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
+
+    assert_sized::<Bar<Bar<A>>>();
+    //~^ ERROR the trait bound `A: std::marker::Sized` is not satisfied
+}
diff --git a/src/test/compile-fail/feature-gate-extern_types.rs b/src/test/compile-fail/feature-gate-extern_types.rs
new file mode 100644
index 00000000000..1203b598df3
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-extern_types.rs
@@ -0,0 +1,15 @@
+// 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.
+
+extern {
+    type T; //~ ERROR extern types are experimental
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-27842.rs b/src/test/compile-fail/issue-27842.rs
index 8c71761df2f..eb28e36dc07 100644
--- a/src/test/compile-fail/issue-27842.rs
+++ b/src/test/compile-fail/issue-27842.rs
@@ -14,7 +14,7 @@ fn main() {
     let _ = tup[0];
     //~^ ERROR cannot index into a value of type
     //~| HELP to access tuple elements, use
-    //~| SUGGESTION let _ = tup.0
+    //~| SUGGESTION tup.0
 
     // the case where we show just a general hint
     let i = 0_usize;
diff --git a/src/test/run-make/extern-fn-with-extern-types/Makefile b/src/test/run-make/extern-fn-with-extern-types/Makefile
new file mode 100644
index 00000000000..8977e14c3ad
--- /dev/null
+++ b/src/test/run-make/extern-fn-with-extern-types/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,ctest)
+	$(RUSTC) test.rs
+	$(call RUN,test) || exit 1
diff --git a/src/test/run-make/extern-fn-with-extern-types/ctest.c b/src/test/run-make/extern-fn-with-extern-types/ctest.c
new file mode 100644
index 00000000000..c3d6166fb12
--- /dev/null
+++ b/src/test/run-make/extern-fn-with-extern-types/ctest.c
@@ -0,0 +1,17 @@
+// ignore-license
+#include <stdio.h>
+#include <stdint.h>
+
+typedef struct data {
+    uint32_t magic;
+} data;
+
+data* data_create(uint32_t magic) {
+    static data d;
+    d.magic = magic;
+    return &d;
+}
+
+uint32_t data_get(data* p) {
+    return p->magic;
+}
diff --git a/src/test/run-make/extern-fn-with-extern-types/test.rs b/src/test/run-make/extern-fn-with-extern-types/test.rs
new file mode 100644
index 00000000000..9d6c87885b1
--- /dev/null
+++ b/src/test/run-make/extern-fn-with-extern-types/test.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(extern_types)]
+
+#[link(name = "ctest", kind = "static")]
+extern {
+    type data;
+
+    fn data_create(magic: u32) -> *mut data;
+    fn data_get(data: *mut data) -> u32;
+}
+
+const MAGIC: u32 = 0xdeadbeef;
+fn main() {
+    unsafe {
+        let data = data_create(MAGIC);
+        assert_eq!(data_get(data), MAGIC);
+    }
+}
diff --git a/src/test/run-pass/extern-types-inherent-impl.rs b/src/test/run-pass/extern-types-inherent-impl.rs
new file mode 100644
index 00000000000..4e44af36900
--- /dev/null
+++ b/src/test/run-pass/extern-types-inherent-impl.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that inherent impls can be defined for extern types.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+impl A {
+    fn foo(&self) { }
+}
+
+fn use_foo(x: &A) {
+    x.foo();
+}
+
+fn main() { }
diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs
new file mode 100644
index 00000000000..c6530c3ea77
--- /dev/null
+++ b/src/test/run-pass/extern-types-manual-sync-send.rs
@@ -0,0 +1,28 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that unsafe impl for Sync/Send can be provided for extern types.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+unsafe impl Sync for A { }
+unsafe impl Send for A { }
+
+fn assert_sync<T: ?Sized + Sync>() { }
+fn assert_send<T: ?Sized + Send>() { }
+
+fn main() {
+    assert_sync::<A>();
+    assert_send::<A>();
+}
diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs
new file mode 100644
index 00000000000..628a570665a
--- /dev/null
+++ b/src/test/run-pass/extern-types-pointer-cast.rs
@@ -0,0 +1,40 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that pointers to extern types can be casted from/to usize,
+// despite being !Sized.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+struct Foo {
+    x: u8,
+    tail: A,
+}
+
+struct Bar<T: ?Sized> {
+    x: u8,
+    tail: T,
+}
+
+#[cfg(target_pointer_width = "32")]
+const MAGIC: usize = 0xdeadbeef;
+#[cfg(target_pointer_width = "64")]
+const MAGIC: usize = 0x12345678deadbeef;
+
+fn main() {
+    assert_eq!((MAGIC as *const A) as usize, MAGIC);
+    assert_eq!((MAGIC as *const Foo) as usize, MAGIC);
+    assert_eq!((MAGIC as *const Bar<A>) as usize, MAGIC);
+    assert_eq!((MAGIC as *const Bar<Bar<A>>) as usize, MAGIC);
+}
diff --git a/src/test/run-pass/extern-types-size_of_val.rs b/src/test/run-pass/extern-types-size_of_val.rs
new file mode 100644
index 00000000000..0aabce99deb
--- /dev/null
+++ b/src/test/run-pass/extern-types-size_of_val.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(extern_types)]
+
+use std::mem::{size_of_val, align_of_val};
+
+extern {
+    type A;
+}
+
+fn main() {
+    let x: &A = unsafe {
+        &*(1usize as *const A)
+    };
+
+    assert_eq!(size_of_val(x), 0);
+    assert_eq!(align_of_val(x), 1);
+}
diff --git a/src/test/run-pass/extern-types-thin-pointer.rs b/src/test/run-pass/extern-types-thin-pointer.rs
new file mode 100644
index 00000000000..c2444a58b5a
--- /dev/null
+++ b/src/test/run-pass/extern-types-thin-pointer.rs
@@ -0,0 +1,51 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that pointers and references to extern types are thin, ie they have the same size and
+// alignment as a pointer to ().
+
+#![feature(extern_types)]
+
+use std::mem::{align_of, size_of};
+
+extern {
+    type A;
+}
+
+struct Foo {
+    x: u8,
+    tail: A,
+}
+
+struct Bar<T: ?Sized> {
+    x: u8,
+    tail: T,
+}
+
+fn assert_thin<T: ?Sized>() {
+    assert_eq!(size_of::<*const T>(), size_of::<*const ()>());
+    assert_eq!(align_of::<*const T>(), align_of::<*const ()>());
+
+    assert_eq!(size_of::<*mut T>(), size_of::<*mut ()>());
+    assert_eq!(align_of::<*mut T>(), align_of::<*mut ()>());
+
+    assert_eq!(size_of::<&T>(), size_of::<&()>());
+    assert_eq!(align_of::<&T>(), align_of::<&()>());
+
+    assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>());
+    assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>());
+}
+
+fn main() {
+    assert_thin::<A>();
+    assert_thin::<Foo>();
+    assert_thin::<Bar<A>>();
+    assert_thin::<Bar<Bar<A>>>();
+}
diff --git a/src/test/run-pass/extern-types-trait-impl.rs b/src/test/run-pass/extern-types-trait-impl.rs
new file mode 100644
index 00000000000..0f61c936deb
--- /dev/null
+++ b/src/test/run-pass/extern-types-trait-impl.rs
@@ -0,0 +1,35 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that traits can be implemented for extern types.
+
+#![feature(extern_types)]
+
+extern {
+    type A;
+}
+
+trait Foo {
+    fn foo(&self) { }
+}
+
+impl Foo for A {
+    fn foo(&self) { }
+}
+
+fn assert_foo<T: ?Sized + Foo>() { }
+
+fn use_foo<T: ?Sized + Foo>(x: &Foo) {
+    x.foo();
+}
+
+fn main() {
+    assert_foo::<A>();
+}
diff --git a/src/test/ui/lint/unused_parens_json_suggestion.stderr b/src/test/ui/lint/unused_parens_json_suggestion.stderr
index 4b4dd92855d..701334d8890 100644
--- a/src/test/ui/lint/unused_parens_json_suggestion.stderr
+++ b/src/test/ui/lint/unused_parens_json_suggestion.stderr
@@ -1 +1 @@
-{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":"    let _a = 1 / (2 + 3);"}],"rendered":null}
+{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":"    let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":null}],"rendered":null}
diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs
new file mode 100644
index 00000000000..20c24d64050
--- /dev/null
+++ b/src/test/ui/lint/use_suggestion_json.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --error-format json
+
+// The output for humans should just highlight the whole span without showing
+// the suggested replacement, but we also want to test that suggested
+// replacement only removes one set of parentheses, rather than naïvely
+// stripping away any starting or ending parenthesis characters—hence this
+// test of the JSON error format.
+
+fn main() {
+    let x: Iter;
+}
diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr
new file mode 100644
index 00000000000..2ebe212b93d
--- /dev/null
+++ b/src/test/ui/lint/use_suggestion_json.stderr
@@ -0,0 +1,2 @@
+{"message":"cannot find type `Iter` in this scope","code":{"code":"E0412","explanation":"/nThe type name used is not in scope./n/nErroneous code examples:/n/n```compile_fail,E0412/nimpl Something {} // error: type name `Something` is not in scope/n/n// or:/n/ntrait Foo {/n    fn bar(N); // error: type name `N` is not in scope/n}/n/n// or:/n/nfn foo(x: T) {} // type name `T` is not in scope/n```/n/nTo fix this error, please verify you didn't misspell the type name, you did/ndeclare it or imported it into the scope. Examples:/n/n```/nstruct Something;/n/nimpl Something {} // ok!/n/n// or:/n/ntrait Foo {/n    type N;/n/n    fn bar(_: Self::N); // ok!/n}/n/n// or:/n/nfn foo<T>(x: T) {} // ok!/n```/n/nAnother case that causes this error is when a type is imported into a parent/nmodule. To fix this, you can follow the suggestion and use File directly or/n`use super::File;` which will import the types from the parent namespace. An/nexample that causes this error is below:/n/n```compile_fail,E0412/nuse std::fs::File;/n/nmod foo {/n    fn some_function(f: File) {}/n}/n```/n/n```/nuse std::fs::File;/n/nmod foo {/n    // either/n    use super::File;/n    // or/n    // use std::fs::File;/n    fn foo(f: File) {}/n}/n# fn main() {} // don't insert it for us; that'll break imports/n```/n"},"level":"error","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":862,"byte_end":866,"line_start":20,"line_end":20,"column_start":12,"column_end":16,"is_primary":true,"text":[{"text":"    let x: Iter;","highlight_start":12,"highlight_end":16}],"label":"not found in this scope","suggested_replacement":null,"expansion":null}],"children":[{"message":"possible candidates are found in other modules, you can import them into scope","code":null,"level":"help","spans":[{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::binary_heap::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::btree_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_map::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::hash_set::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::linked_list::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::collections::vec_deque::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::option::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::path::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::result::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::slice::Iter;/n/n","expansion":null},{"file_name":"$DIR/use_suggestion_json.rs","byte_start":839,"byte_end":839,"line_start":19,"line_end":19,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"fn main() {","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":"use std::sync::mpsc::Iter;/n/n","expansion":null}],"children":[],"rendered":null}],"rendered":null}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":null}
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 77ee93c3007..8e9cd1a12fa 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -36,6 +36,7 @@ struct DiagnosticSpan {
     column_end: usize,
     is_primary: bool,
     label: Option<String>,
+    suggested_replacement: Option<String>,
     expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
 }
 
@@ -164,15 +165,15 @@ fn push_expected_errors(expected_errors: &mut Vec<Error>,
     }
 
     // If the message has a suggestion, register that.
-    if let Some(ref rendered) = diagnostic.rendered {
-        let start_line = primary_spans.iter().map(|s| s.line_start).min().expect("\
-            every suggestion should have at least one span");
-        for (index, line) in rendered.lines().enumerate() {
-            expected_errors.push(Error {
-                line_num: start_line + index,
-                kind: Some(ErrorKind::Suggestion),
-                msg: line.to_string(),
-            });
+    for span in primary_spans {
+        if let Some(ref suggested_replacement) = span.suggested_replacement {
+            for (index, line) in suggested_replacement.lines().enumerate() {
+                expected_errors.push(Error {
+                    line_num: span.line_start + index,
+                    kind: Some(ErrorKind::Suggestion),
+                    msg: line.to_string(),
+                });
+            }
         }
     }