about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Lietar <paul@lietar.net>2017-09-03 19:53:58 +0100
committerPaul LiƩtar <lietar@google.com>2017-10-27 23:01:34 +0200
commit77f7e85d7f4ebcc1a291edae95a3747b0e54d7fa (patch)
tree3a10519372a957925738544a8a7cb651139e7fb5
parentbed9a85c40f98ab8f4445b66d285d4108de9ad21 (diff)
downloadrust-77f7e85d7f4ebcc1a291edae95a3747b0e54d7fa.tar.gz
rust-77f7e85d7f4ebcc1a291edae95a3747b0e54d7fa.zip
Implement RFC 1861: Extern types
-rw-r--r--src/libcore/ptr.rs16
-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/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.rs2
-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/common.rs13
-rw-r--r--src/librustc_trans/context.rs4
-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_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/libsyntax/ast.rs5
-rw-r--r--src/libsyntax/feature_gate.rs27
-rw-r--r--src/libsyntax/fold.rs1
-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/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
81 files changed, 737 insertions, 120 deletions
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 01990f61fee..4a52ec5ee78 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -485,8 +485,9 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is_null(self) -> bool where T: Sized {
-        self == null()
+    pub fn is_null(self) -> bool {
+        // cast to () pointer, as T may not be sized
+        self as *const () == null()
     }
 
     /// Returns `None` if the pointer is null, or else returns a reference to
@@ -517,7 +518,7 @@ impl<T: ?Sized> *const T {
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
+    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         if self.is_null() {
             None
         } else {
@@ -1116,8 +1117,9 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
-    pub fn is_null(self) -> bool where T: Sized {
-        self == null_mut()
+    pub fn is_null(self) -> bool {
+        // cast to () pointer, as T may not be sized
+        self as *mut () == null_mut()
     }
 
     /// Returns `None` if the pointer is null, or else returns a reference to
@@ -1148,7 +1150,7 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> where T: Sized {
+    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
         if self.is_null() {
             None
         } else {
@@ -1272,7 +1274,7 @@ impl<T: ?Sized> *mut T {
     /// ```
     #[stable(feature = "ptr_as_ref", since = "1.9.0")]
     #[inline]
-    pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> where T: Sized {
+    pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
         if self.is_null() {
             None
         } else {
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/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..2e7185cdc0c 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;
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/common.rs b/src/librustc_trans/common.rs
index e3856cabcf9..7c1b0b07d28 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -152,6 +152,19 @@ pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bo
     ty.is_freeze(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),
+    }
+}
+
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
 *
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 6fd24c1786c..aca5fda2665 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -301,6 +301,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         common::type_is_freeze(self.tcx, ty)
     }
 
+    pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
+        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_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/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/parse/parser.rs b/src/libsyntax/parse/parser.rs
index a2c431dc8b1..1d990f16ac9 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5671,6 +5671,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
@@ -6145,6 +6163,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/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>();
+}