From 907c7a33574bf67cd902ed19309c5b1b9f497f9a Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Sun, 3 Sep 2017 19:53:58 +0100
Subject: [PATCH 1/7] Implement RFC 1861: Extern types

---
 src/libcore/ptr.rs                            | 16 +++--
 src/librustc/hir/def.rs                       |  4 +-
 src/librustc/hir/intravisit.rs                |  1 +
 src/librustc/hir/lowering.rs                  |  3 +
 src/librustc/hir/mod.rs                       |  3 +
 src/librustc/hir/print.rs                     |  7 ++
 src/librustc/ich/impls_hir.rs                 |  4 +-
 src/librustc/ich/impls_ty.rs                  |  6 +-
 src/librustc/infer/freshen.rs                 |  1 +
 src/librustc/middle/resolve_lifetime.rs       |  3 +
 src/librustc/traits/coherence.rs              |  4 ++
 src/librustc/traits/error_reporting.rs        |  1 +
 src/librustc/traits/select.rs                 | 12 +++-
 src/librustc/ty/context.rs                    |  6 +-
 src/librustc/ty/error.rs                      |  1 +
 src/librustc/ty/fast_reject.rs                |  6 ++
 src/librustc/ty/flags.rs                      |  3 +-
 src/librustc/ty/item_path.rs                  |  7 +-
 src/librustc/ty/layout.rs                     | 22 ++++---
 src/librustc/ty/mod.rs                        |  2 +-
 src/librustc/ty/outlives.rs                   |  1 +
 src/librustc/ty/relate.rs                     |  6 ++
 src/librustc/ty/structural_impls.rs           |  4 +-
 src/librustc/ty/sty.rs                        | 11 ++--
 src/librustc/ty/util.rs                       |  6 +-
 src/librustc/ty/walk.rs                       |  3 +-
 src/librustc/ty/wf.rs                         |  3 +-
 src/librustc/util/ppaux.rs                    |  3 +-
 src/librustc_lint/types.rs                    |  3 +
 src/librustc_metadata/decoder.rs              |  1 +
 src/librustc_metadata/encoder.rs              |  1 +
 src/librustc_metadata/schema.rs               |  2 +
 src/librustc_passes/ast_validation.rs         |  2 +-
 src/librustc_privacy/lib.rs                   | 16 ++++-
 src/librustc_resolve/build_reduced_graph.rs   | 13 ++--
 src/librustc_resolve/lib.rs                   |  4 +-
 src/librustc_save_analysis/dump_visitor.rs    |  7 ++
 src/librustc_save_analysis/lib.rs             |  3 +
 src/librustc_save_analysis/sig.rs             | 17 +++++
 src/librustc_trans/collector.rs               |  4 +-
 src/librustc_trans/common.rs                  | 13 ++++
 src/librustc_trans/context.rs                 |  4 ++
 src/librustc_trans/debuginfo/metadata.rs      | 16 +++++
 src/librustc_trans/debuginfo/type_names.rs    |  1 +
 src/librustc_trans/intrinsic.rs               | 14 ++--
 src/librustc_trans/mir/constant.rs            |  6 +-
 src/librustc_trans/mir/lvalue.rs              | 18 ++++--
 src/librustc_trans/mir/rvalue.rs              |  2 +-
 src/librustc_trans/trans_item.rs              |  1 +
 src/librustc_trans/type_of.rs                 |  8 +--
 src/librustc_typeck/astconv.rs                |  3 +-
 src/librustc_typeck/check/cast.rs             | 64 +++++++++++--------
 src/librustc_typeck/check/method/probe.rs     |  3 +
 src/librustc_typeck/check/method/suggest.rs   |  1 +
 .../coherence/inherent_impls.rs               |  3 +
 src/librustc_typeck/coherence/orphan.rs       | 11 ++--
 src/librustc_typeck/collect.rs                |  9 ++-
 src/librustc_typeck/variance/constraints.rs   |  2 +-
 src/librustdoc/clean/mod.rs                   | 17 +++++
 src/librustdoc/html/item_type.rs              |  7 +-
 src/librustdoc/html/render.rs                 |  4 +-
 src/librustdoc/passes/mod.rs                  |  2 +-
 src/libsyntax/ast.rs                          |  5 +-
 src/libsyntax/feature_gate.rs                 | 27 ++++++--
 src/libsyntax/fold.rs                         |  1 +
 src/libsyntax/parse/parser.rs                 | 22 +++++++
 src/libsyntax/print/pprust.rs                 |  7 ++
 src/libsyntax/visit.rs                        |  1 +
 .../extern-types-distinct-types.rs            | 22 +++++++
 .../extern-types-not-sync-send.rs             | 28 ++++++++
 src/test/compile-fail/extern-types-unsized.rs | 43 +++++++++++++
 .../compile-fail/feature-gate-extern_types.rs | 15 +++++
 .../extern-fn-with-extern-types/Makefile      |  5 ++
 .../extern-fn-with-extern-types/ctest.c       | 17 +++++
 .../extern-fn-with-extern-types/test.rs       | 27 ++++++++
 .../run-pass/extern-types-inherent-impl.rs    | 27 ++++++++
 .../run-pass/extern-types-manual-sync-send.rs | 28 ++++++++
 .../run-pass/extern-types-pointer-cast.rs     | 40 ++++++++++++
 src/test/run-pass/extern-types-size_of_val.rs | 26 ++++++++
 .../run-pass/extern-types-thin-pointer.rs     | 51 +++++++++++++++
 src/test/run-pass/extern-types-trait-impl.rs  | 35 ++++++++++
 81 files changed, 739 insertions(+), 119 deletions(-)
 create mode 100644 src/test/compile-fail/extern-types-distinct-types.rs
 create mode 100644 src/test/compile-fail/extern-types-not-sync-send.rs
 create mode 100644 src/test/compile-fail/extern-types-unsized.rs
 create mode 100644 src/test/compile-fail/feature-gate-extern_types.rs
 create mode 100644 src/test/run-make/extern-fn-with-extern-types/Makefile
 create mode 100644 src/test/run-make/extern-fn-with-extern-types/ctest.c
 create mode 100644 src/test/run-make/extern-fn-with-extern-types/test.rs
 create mode 100644 src/test/run-pass/extern-types-inherent-impl.rs
 create mode 100644 src/test/run-pass/extern-types-manual-sync-send.rs
 create mode 100644 src/test/run-pass/extern-types-pointer-cast.rs
 create mode 100644 src/test/run-pass/extern-types-size_of_val.rs
 create mode 100644 src/test/run-pass/extern-types-thin-pointer.rs
 create mode 100644 src/test/run-pass/extern-types-trait-impl.rs

diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 4041a3760e5ca..4d7d151ca8983 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -487,8 +487,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
@@ -519,7 +520,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 {
@@ -1118,8 +1119,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
@@ -1150,7 +1152,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 {
@@ -1274,7 +1276,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 4e0c6479abf14..64bcdc7920a01 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 1755b3bca0572..12dea2ca382e4 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 411cdde3190b2..2a8e4e61272a7 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1715,6 +1715,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 bff71155440a3..ca96ccdaacfcb 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1904,6 +1904,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_ {
@@ -1911,6 +1913,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 5daffe667fde5..57ea3c3b4362a 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -477,6 +477,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 96d5940caf6a4..bf12a0a585758 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -968,7 +968,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_ {
@@ -1077,6 +1078,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 2bbf807807bad..b1c18d5d934e4 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -606,8 +606,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);
@@ -626,6 +625,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 c274f8bda9fb0..41e7dffe54dc1 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 d0c5460fa9714..e215579331e17 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 f3682f8d35d84..7fd20c0a41a9e 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -305,6 +305,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 c7c8141f4f768..5e9b853895588 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 00f0672822fc1..2ecb82b77d34c 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1707,6 +1707,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
@@ -2024,7 +2030,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()))
@@ -2068,7 +2074,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
             }
@@ -2150,6 +2157,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 315ba622ccf6d..5b9639507a718 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1576,7 +1576,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());
@@ -1827,6 +1827,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 52a8389bd8f5f..5cfa72c07126f 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 490bfe78a9a1f..138f6af77c658 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 9ece719c76470..63c646dbd2310 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 a8ccb3e269ffc..98c55331f8a10 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 1709f9ed2df1c..491fa2a240cce 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 2c1b3e28ffb00..cdc5e1c404411 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1724,7 +1724,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 657ed4077911c..9d29c2adb1869 100644
--- a/src/librustc/ty/outlives.rs
+++ b/src/librustc/ty/outlives.rs
@@ -178,6 +178,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 309880ba06333..376cdc462e82f 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 54d55748c8e3a..5f1448cd1f18e 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 a203e290dbaeb..d2b45eccc9dc7 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -105,6 +105,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,
 
@@ -1165,13 +1167,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 {
@@ -1395,6 +1390,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,
         }
@@ -1444,6 +1440,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 27819f551b9b3..1675c3f5a8319 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 df07844ccebaf..448ad4cf675c7 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 41e27fca3f320..c631e2c4db51b 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 214973e308586..4c6b7d3e5b343 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};
 
@@ -788,6 +788,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
             TyError => write!(f, "[type error]"),
             TyParam(ref param_ty) => write!(f, "{}", param_ty),
             TyAdt(def, substs) => parameterized(f, substs, def.did, &[]),
+            TyForeign(def_id) => parameterized(f, subst::Substs::empty(), def_id, &[]),
             TyDynamic(data, r) => {
                 write!(f, "{}", data)?;
                 let r = r.to_string();
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index d3a5d52b295af..ca2c1bd3a1807 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -615,6 +615,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 FfiSafe
             }
 
+            ty::TyForeign(..) => FfiSafe,
+
             ty::TyParam(..) |
             ty::TyInfer(..) |
             ty::TyError |
@@ -717,6 +719,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 65cf15e5a0ec7..909e01376b92c 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 6b49be3e12192..abe2b6d0c1b19 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 dad0d26d2715d..a1b5d052e1cda 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -291,6 +291,7 @@ pub enum EntryKind<'tcx> {
     ForeignImmStatic,
     ForeignMutStatic,
     ForeignMod,
+    ForeignType,
     GlobalAsm,
     Type,
     Enum(ReprOptions),
@@ -324,6 +325,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 efb5b03180998..d2e8b87269e20 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 e7a1dd6b043b1..ac0ddbf3f7178 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 a4d1ae1621571..5ddde096d72b3 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 36cd69f91b9c3..c6fc42c501e1f 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -464,7 +464,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 {
@@ -703,6 +704,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 3e730cf836523..49e3ce2f5ed0d 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 {
@@ -1536,6 +1537,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 1c6007966afa3..cf2cad1b38c42 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 c7e00245d6350..d540b2bf6e825 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -807,6 +807,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/collector.rs b/src/librustc_trans/collector.rs
index 6fa69de74b0a1..b3a8a25a48983 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -202,7 +202,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};
 
@@ -775,7 +775,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             target_ty: Ty<'tcx>)
                                             -> (Ty<'tcx>, Ty<'tcx>) {
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
-        if !type_is_sized(tcx, inner_source) {
+        if type_has_metadata(tcx, inner_source) {
             (inner_source, inner_target)
         } else {
             tcx.struct_lockstep_tails(inner_source, inner_target)
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 52607904f73c4..8b1976c49a665 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -153,6 +153,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 b394911c9234d..b03bc46b6f5fd 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 8a89bfee4ac26..6799c2ea1c294 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -544,6 +544,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) {
@@ -753,6 +758,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 7bf9d39ea2f25..85467f5bfbd22 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 f78d80a197ca9..e80239175681e 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 9232d73f832e7..45d857fe49910 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -425,11 +425,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()
@@ -460,7 +460,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 6799e52904d34..d939acaccd99c 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 822431eba42f1..777b86387e8bf 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 526b61303e153..9e624d83a5b7c 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -411,6 +411,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             ty::TyUint(ast::UintTy::U128)  => output.push_str("u128"),
             ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
             ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
+            ty::TyForeign(def_id) => self.push_def_path(def_id, output),
             ty::TyAdt(adt_def, substs) => {
                 self.push_def_path(adt_def.did, output);
                 self.push_type_params(substs, iter::empty(), output);
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 992c74b9020c3..cac09a81361f0 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_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 54fd070e93cbc..58a09d5aa65ee 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 9c6cacb9d25f9..7b35b46683099 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 a3b196f99d629..5ff76752bf9a2 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -413,6 +413,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 90c5297b39985..00a6746a8a06c 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -448,6 +448,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 15e15abfb3606..c56a3b91ca37f 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 097720adad447..a5edc95b79b08 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 a36594cb6e557..688f50777dd40 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -935,7 +935,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,
             }
         }
 
@@ -1111,7 +1112,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),
             }
         }
 
@@ -1380,7 +1382,8 @@ fn 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 29da763f334c7..8f2c4ea835089 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -301,7 +301,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 c9afa3646b2da..4b5ac75242d5b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -416,6 +416,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>),
@@ -1642,6 +1644,7 @@ pub enum TypeKind {
     Trait,
     Variant,
     Typedef,
+    Foreign,
 }
 
 pub trait GetDefId {
@@ -1998,6 +2001,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();
@@ -2810,6 +2824,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 f584c4e2f4d9c..c9c5f01f0aea1 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 485e75443fe08..4dd276e8ec907 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2017,6 +2017,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>",
@@ -3627,7 +3628,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
@@ -3656,6 +3657,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 146629486fabd..959543404d8d2 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 0504e889ea10b..137eb89a907f8 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1992,13 +1992,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 4da0df5b0de01..b1ba96f7773b0 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -395,6 +395,9 @@ declare_features! (
 
     // allow `..=` in patterns (RFC 1192)
     (active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
+
+    // extern types
+    (active, extern_types, "1.22.0", Some(43467)),
 );
 
 declare_features! (
@@ -1382,13 +1385,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 03c47b71d02d7..0f4722e87145a 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1067,6 +1067,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 d5ba4b54d9014..f02b46c69f27f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5621,6 +5621,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
@@ -6095,6 +6113,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 959dd4ef30f29..5b735c8717f66 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1111,6 +1111,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 05077d42a0bed..5657300e629d6 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -464,6 +464,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 0000000000000..8b434bbfc6d33
--- /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 0000000000000..2f00cf812e473
--- /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 0000000000000..faa27894806f8
--- /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 0000000000000..1203b598df3c2
--- /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 0000000000000..8977e14c3ad1a
--- /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 0000000000000..c3d6166fb1284
--- /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 0000000000000..9d6c87885b16e
--- /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 0000000000000..4e44af3690064
--- /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 0000000000000..c6530c3ea773a
--- /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 0000000000000..628a570665a33
--- /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 0000000000000..0aabce99debe8
--- /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 0000000000000..c2444a58b5a1b
--- /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 0000000000000..0f61c936deb61
--- /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>();
+}

From da549e116a335c3febbe40b72bb7deeca7039b2d Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Fri, 29 Sep 2017 13:14:36 +0200
Subject: [PATCH 2/7] Mark rustfmt and rls as broken.

Rustfmt needs support for extern types, and rls depends on rustfmt.
---
 src/tools/toolstate.toml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml
index 1700daa0aff14..c36d50ad710e4 100644
--- a/src/tools/toolstate.toml
+++ b/src/tools/toolstate.toml
@@ -29,8 +29,8 @@ miri = "Broken"
 clippy = "Broken"
 
 # ping @nrc
-rls = "Testing"
+rls = "Broken"
 
 # ping @nrc
-rustfmt = "Testing"
+rustfmt = "Broken"
 

From c0cf410878e32fda6f506c17cbe31dedcc321c97 Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Sun, 3 Sep 2017 23:48:02 +0100
Subject: [PATCH 3/7] Add a DynSized trait.

The DynSized trait is implemented by all types which have a size and alignment
known at runtime. This includes every type other than extern types, introduced
in RFC 1861 and implemented in #44295, which are completely opaque.

The main motivation for this trait is to prevent the use of !DynSized types as
struct tails. Consider for example the following types :
```rust
extern {
  type foo;
}

struct A<T: ?Sized> {
    a_x: u8
    a_y: T
}

struct B<T: ?Sized> {
    b_x: u8
    b_y: T
}
```

Before this change, the type `A<B<foo>>` is considered well-formed. However,
the alignment of `B<foo>` and thus the offset of the `a_y` field depends on the
alignment of `foo`, which is unknown.

By introducing this new trait, struct tails are now required to implement
`DynSized`, such that their alignment is known. The trait is an implicit bound,
making `A<B<foo>>` ill-formed.

Just like the `Sized` trait, the default bound can be opted-out by using
`?DynSized`.
---
 src/libcore/marker.rs                   |  97 +++++++++++++++++------
 src/libcore/ptr.rs                      |   2 +-
 src/librustc/dep_graph/dep_node.rs      |   2 +
 src/librustc/lib.rs                     |   2 +-
 src/librustc/middle/lang_items.rs       |   1 +
 src/librustc/traits/error_reporting.rs  |   3 +
 src/librustc/traits/mod.rs              |   3 +
 src/librustc/traits/select.rs           |  56 +++++++++++++
 src/librustc/traits/structural_impls.rs |   3 +
 src/librustc/ty/maps/config.rs          |   6 ++
 src/librustc/ty/maps/mod.rs             |   6 ++
 src/librustc/ty/mod.rs                  |  98 +++++++++++++++++++++++
 src/librustc/ty/util.rs                 |  25 +++++-
 src/librustc/ty/wf.rs                   |  14 +++-
 src/librustc/util/ppaux.rs              |  10 ++-
 src/librustc_passes/ast_validation.rs   |  35 +++-----
 src/librustc_trans/common.rs            |   4 +
 src/librustc_trans/context.rs           |   4 +
 src/librustc_trans/intrinsic.rs         |   8 +-
 src/librustc_trans/mir/lvalue.rs        |  15 ++--
 src/librustc_typeck/astconv.rs          |  11 +++
 src/librustc_typeck/check/wfcheck.rs    |  11 +++
 src/librustc_typeck/coherence/mod.rs    |  10 ++-
 src/librustc_typeck/collect.rs          | 101 ++++++++++++++++--------
 src/libstd/lib.rs                       |   1 +
 src/libstd/panic.rs                     |  31 +++++++-
 26 files changed, 452 insertions(+), 107 deletions(-)

diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index e8fd729b638be..6c003506846b9 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -40,6 +40,16 @@ use hash::Hasher;
 /// [ub]: ../../reference/behavior-considered-undefined.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "send"]
+#[cfg(not(stage0))]
+#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
+pub unsafe trait Send: ?DynSized {
+    // empty.
+}
+
+/// docs
+#[stable(feature = "rust1", since = "1.0.0")]
+#[lang = "send"]
+#[cfg(stage0)]
 #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"]
 pub unsafe trait Send {
     // empty.
@@ -49,9 +59,9 @@ pub unsafe trait Send {
 unsafe impl Send for .. { }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Send for *const T { }
+impl<T: ?DynSized> !Send for *const T { }
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Send for *mut T { }
+impl<T: ?DynSized> !Send for *mut T { }
 
 /// Types with a constant size known at compile time.
 ///
@@ -94,6 +104,29 @@ pub trait Sized {
     // Empty.
 }
 
+/// Types with a size known at run time.
+///
+/// This trait is implemented both by `Sized` types, and by dynamically sized
+/// types such as slices and [trait objects]. [Extern types], whose size is not
+/// known, even at runtime, do not implement this trait.
+///
+/// All traits and type parameters have an implicit bound of `DynSized`. The
+/// special syntax `?DynSized` can be used to remove this bound if it's not
+/// appropriate.
+///
+/// [trait object]: ../../book/first-edition/trait-objects.html
+#[cfg(not(stage0))]
+#[unstable(feature = "dynsized", issue = "0")]
+#[lang = "dynsized"]
+#[rustc_on_unimplemented = "`{Self}` does not have a size known at run-time"]
+#[fundamental]
+pub trait DynSized: ?DynSized {
+    // Empty.
+}
+
+#[cfg(stage0)]
+use self::Sized as DynSized; // This is just so we don't have to stage too much stuff
+
 /// Types that can be "unsized" to a dynamically-sized type.
 ///
 /// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
@@ -343,6 +376,16 @@ pub trait Copy : Clone {
 /// [transmute]: ../../std/mem/fn.transmute.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "sync"]
+#[cfg(not(stage0))]
+#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
+pub unsafe trait Sync: ?DynSized {
+    // Empty
+}
+
+/// docs
+#[stable(feature = "rust1", since = "1.0.0")]
+#[lang = "sync"]
+#[cfg(stage0)]
 #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"]
 pub unsafe trait Sync {
     // Empty
@@ -352,56 +395,56 @@ pub unsafe trait Sync {
 unsafe impl Sync for .. { }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Sync for *const T { }
+impl<T: ?DynSized> !Sync for *const T { }
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Sync for *mut T { }
+impl<T: ?DynSized> !Sync for *mut T { }
 
 macro_rules! impls{
     ($t: ident) => (
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> Hash for $t<T> {
+        impl<T:?DynSized> Hash for $t<T> {
             #[inline]
             fn hash<H: Hasher>(&self, _: &mut H) {
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> cmp::PartialEq for $t<T> {
+        impl<T:?DynSized> cmp::PartialEq for $t<T> {
             fn eq(&self, _other: &$t<T>) -> bool {
                 true
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> cmp::Eq for $t<T> {
+        impl<T:?DynSized> cmp::Eq for $t<T> {
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> cmp::PartialOrd for $t<T> {
+        impl<T:?DynSized> cmp::PartialOrd for $t<T> {
             fn partial_cmp(&self, _other: &$t<T>) -> Option<cmp::Ordering> {
                 Option::Some(cmp::Ordering::Equal)
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> cmp::Ord for $t<T> {
+        impl<T:?DynSized> cmp::Ord for $t<T> {
             fn cmp(&self, _other: &$t<T>) -> cmp::Ordering {
                 cmp::Ordering::Equal
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> Copy for $t<T> { }
+        impl<T:?DynSized> Copy for $t<T> { }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> Clone for $t<T> {
+        impl<T:?DynSized> Clone for $t<T> {
             fn clone(&self) -> $t<T> {
                 $t
             }
         }
 
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T:?Sized> Default for $t<T> {
+        impl<T:?DynSized> Default for $t<T> {
             fn default() -> $t<T> {
                 $t
             }
@@ -544,29 +587,33 @@ macro_rules! impls{
 /// [drop check]: ../../nomicon/dropck.html
 #[lang = "phantom_data"]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct PhantomData<T:?Sized>;
+pub struct PhantomData<T:?DynSized>;
 
 impls! { PhantomData }
 
-mod impls {
-    #[stable(feature = "rust1", since = "1.0.0")]
-    unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
-    #[stable(feature = "rust1", since = "1.0.0")]
-    unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {}
-}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, T: Sync + ?DynSized> Send for &'a T {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<'a, T: Send + ?DynSized> Send for &'a mut T {}
 
 /// Compiler-internal trait used to determine whether a type contains
 /// any `UnsafeCell` internally, but not through an indirection.
 /// This affects, for example, whether a `static` of that type is
 /// placed in read-only static memory or writable static memory.
 #[lang = "freeze"]
+#[cfg(not(stage0))]
+unsafe trait Freeze: ?DynSized {}
+
+/// docs
+#[lang = "freeze"]
+#[cfg(stage0)]
 unsafe trait Freeze {}
 
 unsafe impl Freeze for .. {}
 
-impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
-unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
-unsafe impl<T: ?Sized> Freeze for *const T {}
-unsafe impl<T: ?Sized> Freeze for *mut T {}
-unsafe impl<'a, T: ?Sized> Freeze for &'a T {}
-unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {}
+impl<T: ?DynSized> !Freeze for UnsafeCell<T> {}
+unsafe impl<T: ?DynSized> Freeze for PhantomData<T> {}
+unsafe impl<T: ?DynSized> Freeze for *const T {}
+unsafe impl<T: ?DynSized> Freeze for *mut T {}
+unsafe impl<'a, T: ?DynSized> Freeze for &'a T {}
+unsafe impl<'a, T: ?DynSized> Freeze for &'a mut T {}
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 4d7d151ca8983..60ff90de77bfa 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -58,7 +58,7 @@ pub use intrinsics::write_bytes;
 #[stable(feature = "drop_in_place", since = "1.8.0")]
 #[lang="drop_in_place"]
 #[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+pub unsafe fn drop_in_place<T: ?DynSized>(to_drop: *mut T) {
     // Code here does not matter - this is replaced by the
     // real drop glue by the compiler.
     drop_in_place(to_drop);
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 7a78765365db0..b14543afa8e5a 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -477,6 +477,7 @@ define_dep_nodes!( <'tcx>
     [] IsForeignItem(DefId),
     [] TypeParamPredicates { item_id: DefId, param_id: DefId },
     [] SizedConstraint(DefId),
+    [] DynSizedConstraint(DefId),
     [] DtorckConstraint(DefId),
     [] AdtDestructor(DefId),
     [] AssociatedItemDefIds(DefId),
@@ -492,6 +493,7 @@ define_dep_nodes!( <'tcx>
 
     [anon] IsCopy,
     [anon] IsSized,
+    [anon] IsDynSized,
     [anon] IsFreeze,
     [anon] NeedsDrop,
     [anon] Layout,
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 1e90aa47267ff..a047ce5357984 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -59,7 +59,7 @@
 #![cfg_attr(stage0, feature(const_fn))]
 #![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
 
-#![recursion_limit="256"]
+#![recursion_limit="512"]
 
 extern crate arena;
 #[macro_use] extern crate bitflags;
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 679c4f17a6c03..28f4a3fbbb182 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -230,6 +230,7 @@ language_item_table! {
 
     SendTraitLangItem,               "send",                    send_trait;
     SizedTraitLangItem,              "sized",                   sized_trait;
+    DynSizedTraitLangItem,           "dynsized",                dynsized_trait;
     UnsizeTraitLangItem,             "unsize",                  unsize_trait;
     CopyTraitLangItem,               "copy",                    copy_trait;
     CloneTraitLangItem,              "clone",                   clone_trait;
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 5e9b853895588..8e26065d66b7a 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -1125,6 +1125,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             ObligationCauseCode::StructInitializerSized => {
                 err.note("structs must have a statically known size to be initialized");
             }
+            ObligationCauseCode::FieldDynSized => {
+                err.note("the last field of a struct or tuple must have a dynamically sized type");
+            }
             ObligationCauseCode::FieldSized(ref item) => {
                 match *item {
                     AdtKind::Struct => {
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a1817f181066c..1f14e999a9edd 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -137,6 +137,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// Types of fields (other than the last) in a struct must be sized.
     FieldSized(AdtKind),
 
+    /// Last field of a struct must be DynSized.
+    FieldDynSized,
+
     /// Constant expressions must be sized.
     ConstSized,
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 2ecb82b77d34c..646926a98bf51 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1348,6 +1348,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             let sized_conditions = self.sized_conditions(obligation);
             self.assemble_builtin_bound_candidates(sized_conditions,
                                                    &mut candidates)?;
+        } else if lang_items.dynsized_trait() == Some(def_id) {
+            // DynSized is never implementable by end-users, it is
+            // always automatically computed.
+            let dynsized_conditions = self.dynsized_conditions(obligation);
+            self.assemble_builtin_bound_candidates(dynsized_conditions,
+                                                   &mut candidates)?;
          } else if lang_items.unsize_trait() == Some(def_id) {
              self.assemble_candidates_for_unsizing(obligation, &mut candidates);
          } else {
@@ -2056,6 +2062,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         }
     }
 
+    fn dynsized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
+                     -> BuiltinImplConditions<'tcx>
+    {
+        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
+
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(
+            obligation.predicate.skip_binder().self_ty());
+
+        match self_ty.sty {
+            ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
+            ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) |
+            ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever |
+            ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) |
+            ty::TyError  => {
+                // safe for everything
+                Where(ty::Binder(Vec::new()))
+            }
+
+            ty::TyTuple(tys, _) => {
+                Where(ty::Binder(tys.last().into_iter().cloned().collect()))
+            }
+
+            ty::TyAdt(def, substs) => {
+                let dynsized_crit = def.dynsized_constraint(self.tcx());
+                // (*) binder moved here
+                Where(ty::Binder(
+                    dynsized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
+                ))
+            }
+
+            ty::TyForeign(..) => Never,
+
+            ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
+            ty::TyInfer(ty::TyVar(_)) => Ambiguous,
+
+            ty::TyInfer(ty::FreshTy(_))
+            | ty::TyInfer(ty::FreshIntTy(_))
+            | ty::TyInfer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}",
+                     self_ty);
+            }
+        }
+    }
+
     fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                      -> BuiltinImplConditions<'tcx>
     {
@@ -2392,6 +2445,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 _ if Some(trait_def) == lang_items.sized_trait() => {
                     self.sized_conditions(obligation)
                 }
+                _ if Some(trait_def) == lang_items.dynsized_trait() => {
+                    self.dynsized_conditions(obligation)
+                }
                 _ if Some(trait_def) == lang_items.copy_trait() => {
                     self.copy_clone_conditions(obligation)
                 }
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index 19ed03aa14917..e659dee19364e 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -211,6 +211,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
             super::SizedReturnType => Some(super::SizedReturnType),
             super::RepeatVec => Some(super::RepeatVec),
             super::FieldSized(item) => Some(super::FieldSized(item)),
+            super::FieldDynSized => Some(super::FieldDynSized),
             super::ConstSized => Some(super::ConstSized),
             super::SharedStatic => Some(super::SharedStatic),
             super::BuiltinDerivedObligation(ref cause) => {
@@ -531,6 +532,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized(_) |
+            super::FieldDynSized |
             super::ConstSized |
             super::SharedStatic |
             super::BlockTailExpression(_) |
@@ -579,6 +581,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
             super::ReturnNoExpression |
             super::RepeatVec |
             super::FieldSized(_) |
+            super::FieldDynSized |
             super::ConstSized |
             super::SharedStatic |
             super::BlockTailExpression(_) |
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index c8520c5be2df5..e759430bda0da 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -45,6 +45,12 @@ impl<'tcx> QueryDescription for queries::is_sized_raw<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::is_dynsized_raw<'tcx> {
+    fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
+        format!("computing whether `{}` is `DynSized`", env.value)
+    }
+}
+
 impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> {
     fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
         format!("computing whether `{}` is freeze", env.value)
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 4bd2d5be6d716..9847c94e19152 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -100,6 +100,7 @@ define_maps! { <'tcx>
     [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
     [] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
     [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
+    [] fn adt_dynsized_constraint: DynSizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
     [] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
 
     /// True if this is a const fn
@@ -244,6 +245,7 @@ define_maps! { <'tcx>
     // `ty.is_copy()`, etc, since that will prune the environment where possible.
     [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
+    [] fn is_dynsized_raw: is_dynsized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
     [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
@@ -398,6 +400,10 @@ fn is_sized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor
     DepConstructor::IsSized
 }
 
+fn is_dynsized_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
+    DepConstructor::IsDynSized
+}
+
 fn is_freeze_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> {
     DepConstructor::IsFreeze
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index cdc5e1c404411..d5b436e8c5844 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1713,6 +1713,18 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    /// Same as `sized_constraint`, but for DynSized
+    pub fn dynsized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] {
+        match queries::adt_dynsized_constraint::try_get(tcx, DUMMY_SP, self.did) {
+            Ok(tys) => tys,
+            Err(mut bug) => {
+                debug!("adt_dynsized_constraint: {:?} is recursive", self);
+                bug.delay_as_bug();
+                tcx.intern_type_list(&[tcx.types.err])
+            }
+        }
+    }
+
     fn sized_constraint_for_ty(&self,
                                tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                ty: Ty<'tcx>)
@@ -1782,6 +1794,74 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
         result
     }
+
+    fn dynsized_constraint_for_ty(&self,
+                                   tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   ty: Ty<'tcx>)
+                                   -> Vec<Ty<'tcx>> {
+        let result = match ty.sty {
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
+            TyStr | TyDynamic(..) | TySlice(_) | TyArray(..) |
+            TyTuple(..) | TyAdt(..) | TyClosure(..) | TyGenerator(..) |
+            TyNever => {
+                vec![]
+            }
+
+            TyForeign(..) | TyError => {
+                // these are never DynSized - return the target type
+                vec![ty]
+            }
+
+            TyProjection(..) | TyAnon(..) => {
+                // must calculate explicitly.
+                // FIXME: consider special-casing always-DynSized projections
+                vec![ty]
+            }
+
+            TyParam(..) => {
+                // perf hack: if there is a `T: Sized` or `T: DynSized` bound, then
+                // we know that `T` is DynSized and do not need to check
+                // it on the impl.
+
+                let sized_trait = match tcx.lang_items().sized_trait() {
+                    Some(x) => x,
+                    _ => return vec![ty]
+                };
+
+                let dynsized_trait = match tcx.lang_items().dynsized_trait() {
+                    Some(x) => x,
+                    _ => return vec![ty]
+                };
+
+                let sized_predicate = Binder(TraitRef {
+                    def_id: sized_trait,
+                    substs: tcx.mk_substs_trait(ty, &[])
+                }).to_predicate();
+
+                let dynsized_predicate = Binder(TraitRef {
+                    def_id: dynsized_trait,
+                    substs: tcx.mk_substs_trait(ty, &[])
+                }).to_predicate();
+
+                let predicates = tcx.predicates_of(self.did).predicates;
+                if predicates.into_iter().any(|p| {
+                    p == sized_predicate || p == dynsized_predicate
+                }) {
+                    vec![]
+                } else {
+                    vec![ty]
+                }
+            }
+
+            TyInfer(..) => {
+                bug!("unexpected type `{:?}` in dynsized_constraint_for_ty",
+                     ty)
+            }
+        };
+        debug!("dynsized_constraint_for_ty({:?}) = {:?}", ty, result);
+        result
+    }
 }
 
 impl<'a, 'gcx, 'tcx> VariantDef {
@@ -2371,6 +2451,22 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     result
 }
 
+fn adt_dynsized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  def_id: DefId)
+                                  -> &'tcx [Ty<'tcx>] {
+    let def = tcx.adt_def(def_id);
+
+    let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| {
+        v.fields.last()
+    }).flat_map(|f| {
+        def.dynsized_constraint_for_ty(tcx, tcx.type_of(f.did))
+    }).collect::<Vec<_>>());
+
+    debug!("adt_dynsized_constraint: {:?} => {:?}", def, result);
+
+    result
+}
+
 /// Calculates the dtorck constraint for a type.
 fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    def_id: DefId)
@@ -2493,6 +2589,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         associated_item,
         associated_item_def_ids,
         adt_sized_constraint,
+        adt_dynsized_constraint,
         adt_dtorck_constraint,
         def_span,
         param_env,
@@ -2507,6 +2604,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
 pub fn provide_extern(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         adt_sized_constraint,
+        adt_dynsized_constraint,
         adt_dtorck_constraint,
         trait_impls_of: trait_def::trait_impls_of_provider,
         param_env,
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 1675c3f5a8319..c0f81b0c1a9bc 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -799,11 +799,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
     pub fn is_sized(&'tcx self,
                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     param_env: ty::ParamEnv<'tcx>,
-                    span: Span)-> bool
+                    span: Span) -> bool
     {
         tcx.at(span).is_sized_raw(param_env.and(self))
     }
 
+    pub fn is_dynsized(&'tcx self,
+                                tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                param_env: ty::ParamEnv<'tcx>,
+                                span: Span) -> bool
+    {
+        tcx.at(span).is_dynsized_raw(param_env.and(self))
+    }
+
     pub fn is_freeze(&'tcx self,
                      tcx: TyCtxt<'a, 'tcx, 'tcx>,
                      param_env: ty::ParamEnv<'tcx>,
@@ -1064,6 +1072,20 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                        DUMMY_SP))
 }
 
+fn is_dynsized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+                          -> bool
+{
+    let (param_env, ty) = query.into_parts();
+    let trait_def_id = tcx.require_lang_item(lang_items::DynSizedTraitLangItem);
+    tcx.infer_ctxt()
+       .enter(|infcx| traits::type_known_to_meet_bound(&infcx,
+                                                       param_env,
+                                                       ty,
+                                                       trait_def_id,
+                                                       DUMMY_SP))
+}
+
 fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
                            -> bool
@@ -1182,6 +1204,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         is_copy_raw,
         is_sized_raw,
+        is_dynsized_raw,
         is_freeze_raw,
         needs_drop_raw,
         layout_raw,
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index c631e2c4db51b..9ce0dbdca44d7 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -267,6 +267,17 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
         }
     }
 
+    fn require_dynsized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
+        if !subty.has_escaping_regions() {
+            let cause = self.cause(cause);
+            let trait_ref = ty::TraitRef {
+                def_id: self.infcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem),
+                substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
+            };
+            self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
+        }
+    }
+
     /// Push new obligations into `out`. Returns true if it was able
     /// to generate all the predicates needed to validate that `ty0`
     /// is WF. Returns false if `ty0` is an unresolved type variable,
@@ -300,10 +311,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
                 }
 
                 ty::TyTuple(ref tys, _) => {
-                    if let Some((_last, rest)) = tys.split_last() {
+                    if let Some((last, rest)) = tys.split_last() {
                         for elem in rest {
                             self.require_sized(elem, traits::TupleElem);
                         }
+                        self.require_dynsized(last, traits::FieldDynSized);
                     }
                 }
 
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 4c6b7d3e5b343..4fd988839701e 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -811,20 +811,26 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
 
                     let mut first = true;
                     let mut is_sized = false;
+                    let mut is_dynsized = false;
                     write!(f, "impl")?;
                     for predicate in bounds.predicates {
                         if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
-                            // Don't print +Sized, but rather +?Sized if absent.
+                            // Don't print +Sized/DynSized, but rather +?Sized/DynSized if absent.
                             if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
                                 is_sized = true;
                                 continue;
+                            } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() {
+                                is_dynsized = true;
+                                continue;
                             }
 
                             write!(f, "{}{}", if first { " " } else { "+" }, trait_ref)?;
                             first = false;
                         }
                     }
-                    if !is_sized {
+                    if !is_dynsized {
+                        write!(f, "{}?DynSized", if first { " " } else { "+" })?;
+                    } else if !is_sized {
                         write!(f, "{}?Sized", if first { " " } else { "+" })?;
                     }
                     Ok(())
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index d2e8b87269e20..0e6be49a7cd97 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -81,19 +81,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn no_questions_in_bounds(&self, bounds: &TyParamBounds, where_: &str, is_trait: bool) {
-        for bound in bounds {
-            if let TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) = *bound {
-                let mut err = self.err_handler().struct_span_err(poly.span,
-                                    &format!("`?Trait` is not permitted in {}", where_));
-                if is_trait {
-                    err.note(&format!("traits are `?{}` by default", poly.trait_ref.path));
-                }
-                err.emit();
-            }
-        }
-    }
-
     /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus),
     /// or path for ranges.
     ///
@@ -155,16 +142,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             TyKind::TraitObject(ref bounds) => {
                 let mut any_lifetime_bounds = false;
                 for bound in bounds {
-                    if let RegionTyParamBound(ref lifetime) = *bound {
-                        if any_lifetime_bounds {
-                            span_err!(self.session, lifetime.span, E0226,
-                                      "only a single explicit lifetime bound is permitted");
-                            break;
+                    match *bound {
+                        RegionTyParamBound(ref lifetime) => {
+                            if any_lifetime_bounds {
+                                span_err!(self.session, lifetime.span, E0226,
+                                          "only a single explicit lifetime bound is permitted");
+                                break;
+                            }
+                            any_lifetime_bounds = true;
+                        }
+                        TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => {
+                            self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types");
                         }
-                        any_lifetime_bounds = true;
+                        _ => (),
                     }
                 }
-                self.no_questions_in_bounds(bounds, "trait object types", false);
             }
             TyKind::ImplTrait(ref bounds) => {
                 if !bounds.iter()
@@ -229,8 +221,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                 }
             }
-            ItemKind::Trait(.., ref bounds, ref trait_items) => {
-                self.no_questions_in_bounds(bounds, "supertraits", true);
+            ItemKind::Trait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
                         self.check_trait_fn_not_const(sig.constness);
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 8b1976c49a665..e907a120696fa 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -149,6 +149,10 @@ pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> boo
     ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
 }
 
+pub fn type_is_dynsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_dynsized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+}
+
 pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
 }
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index b03bc46b6f5fd..c54bab74582a4 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -297,6 +297,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         common::type_is_sized(self.tcx, ty)
     }
 
+    pub fn type_is_dynsized(&self, ty: Ty<'tcx>) -> bool {
+        common::type_is_dynsized(self.tcx, ty)
+    }
+
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
         common::type_is_freeze(self.tcx, ty)
     }
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index e80239175681e..f84d8f672a01f 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -142,12 +142,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             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) {
+            } else if bcx.ccx.shared().type_is_dynsized(tp_ty) {
                 let (llsize, _) =
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llsize
             } else {
-                C_usize(ccx, 0u64)
+                bug!("trying to get size of !DynSized type")
             }
         }
         "min_align_of" => {
@@ -158,12 +158,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             let tp_ty = substs.type_at(0);
             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) {
+            } else if bcx.ccx.shared().type_is_dynsized(tp_ty) {
                 let (_, llalign) =
                     glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
                 llalign
             } else {
-                C_usize(ccx, 1u64)
+                bug!("trying to get alignment of !DynSized type")
             }
         }
         "pref_align_of" => {
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index d939acaccd99c..8194e4f5ef8df 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -153,21 +153,16 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
                     ptr_val, adt::struct_llfields_index(st, ix)), alignment);
         }
 
-        // If the type of the last field is [T], str or a foreign type, then we don't need to do
-        // any adjusments
+        // If the type of the last field is [T] or str, then we don't need to do
+        // any adjusments. Otherwise it must a trait object.
         match fty.sty {
-            ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => {
+            ty::TySlice(..) | ty::TyStr => {
                 return (bcx.struct_gep(
                         ptr_val, adt::struct_llfields_index(st, ix)), alignment);
             }
-            _ => ()
-        }
 
-        // There's no metadata available, log the case and just do the GEP.
-        if !self.has_extra() {
-            debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
-                ix, Value(ptr_val));
-            return (bcx.struct_gep(ptr_val, adt::struct_llfields_index(st, ix)), alignment);
+            ty::TyDynamic(..) => (),
+            _ => bug!("unexpected DST tail: {:?}", fty.sty),
         }
 
         // We need to get the pointer manually now.
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 58a09d5aa65ee..a5741358bbe73 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1428,6 +1428,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected
 pub struct Bounds<'tcx> {
     pub region_bounds: Vec<ty::Region<'tcx>>,
     pub implicitly_sized: bool,
+    pub implicitly_dynsized: bool,
     pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
     pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
 }
@@ -1449,6 +1450,16 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
             }
         }
 
+        if self.implicitly_dynsized {
+            if let Some(dynsized) = tcx.lang_items().dynsized_trait() {
+                let trait_ref = ty::TraitRef {
+                    def_id: dynsized,
+                    substs: tcx.mk_substs_trait(param_ty, &[])
+                };
+                vec.push(trait_ref.to_predicate());
+            }
+        }
+
         for &region_bound in &self.region_bounds {
             // account for the binder being introduced below; no need to shift `param_ty`
             // because, at present at least, it can only refer to early-bound regions
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index ddbdd20430589..f6f387aa09a8d 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -239,6 +239,17 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
                                                      })));
                 }
 
+                // Last field must be DynSized.
+                if !all_sized && !variant.fields.is_empty() {
+                    let field = &variant.fields[variant.fields.len() - 1];
+                    fcx.register_bound(
+                        field.ty,
+                        fcx.tcx.require_lang_item(lang_items::DynSizedTraitLangItem),
+                        traits::ObligationCause::new(field.span,
+                                                     fcx.body_id,
+                                                     traits::FieldDynSized));
+                }
+
                 // All field types must be well-formed.
                 for field in &variant.fields {
                     fcx.register_wf_obligation(field.ty, field.span, this.code.clone())
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 6109fc57b0dfc..e074f85f5a4fb 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -53,7 +53,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
     let did = Some(trait_def_id);
     let li = tcx.lang_items();
 
-    // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
+    // Disallow *all* explicit impls of `Sized`, `DynSized` and `Unsize` for now.
     if did == li.sized_trait() {
         let span = tcx.span_of_impl(impl_def_id).unwrap();
         struct_span_err!(tcx.sess,
@@ -65,6 +65,14 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
         return;
     }
 
+    if did == li.dynsized_trait() {
+        let span = tcx.span_of_impl(impl_def_id).unwrap();
+        tcx.sess.struct_span_err(span, "explicit impls for the `DynSized` trait are not permitted")
+            .span_label(span, "impl of 'DynSized' not allowed")
+            .emit();
+        return;
+    }
+
     if did == li.unsize_trait() {
         let span = tcx.span_of_impl(impl_def_id).unwrap();
         span_err!(tcx.sess,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 688f50777dd40..e7b2af025f27d 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -27,7 +27,7 @@
 use astconv::{AstConv, Bounds};
 use lint;
 use constrained_type_params as ctp;
-use middle::lang_items::SizedTraitLangItem;
+use middle::lang_items::{DynSizedTraitLangItem, SizedTraitLangItem};
 use middle::const_val::ConstVal;
 use middle::resolve_lifetime as rl;
 use rustc::traits::Reveal;
@@ -1265,10 +1265,35 @@ fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-// Is it marked with ?Sized
-fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
-                                ast_bounds: &[hir::TyParamBound],
-                                span: Span) -> bool
+// Implicit sizing constraint in bounds.
+// This only takes into account defaults and ?Trait bounds,
+// not positive bounds such as trait Tr: Sized { }
+enum ImplicitSizing {
+    Sized,
+    DynSized,
+    None,
+}
+
+impl ImplicitSizing {
+    fn implicitly_sized(&self) -> bool {
+        match *self {
+            ImplicitSizing::Sized => true,
+            ImplicitSizing::DynSized | ImplicitSizing::None => false,
+        }
+    }
+
+    fn implicitly_dynsized(&self) -> bool {
+        match *self {
+            ImplicitSizing::Sized | ImplicitSizing::DynSized => true,
+            ImplicitSizing::None => false,
+        }
+    }
+}
+
+fn find_implicit_sizing<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+                                          ast_bounds: &[hir::TyParamBound],
+                                          span: Span,
+                                          sized_by_default: SizedByDefault) -> ImplicitSizing
 {
     let tcx = astconv.tcx();
 
@@ -1286,27 +1311,36 @@ fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
         }
     }
 
-    let kind_id = tcx.lang_items().require(SizedTraitLangItem);
-    match unbound {
-        Some(ref tpb) => {
-            // FIXME(#8559) currently requires the unbound to be built-in.
-            if let Ok(kind_id) = kind_id {
-                if tpb.path.def != Def::Trait(kind_id) {
-                    tcx.sess.span_warn(span,
-                                       "default bound relaxed for a type parameter, but \
-                                       this does nothing because the given bound is not \
-                                       a default. Only `?Sized` is supported");
-                }
+    let sized_trait = tcx.lang_items().require(SizedTraitLangItem).map(Def::Trait);
+    let dynsized_trait = tcx.lang_items().require(DynSizedTraitLangItem).map(Def::Trait);
+
+    let mut sizing = match sized_by_default {
+        SizedByDefault::Yes => ImplicitSizing::Sized,
+        SizedByDefault::No => ImplicitSizing::DynSized,
+    };
+
+    if let Some(ref tpb) = unbound {
+        if Ok(tpb.path.def) == sized_trait {
+            if sized_by_default == SizedByDefault::No {
+                let mut err = tcx.sess.struct_span_err(span,
+                                    "`?Sized` is not permitted in supertraits");
+
+                err.note("traits are `?Sized` by default");
+                err.emit();
             }
+
+            sizing = ImplicitSizing::DynSized;
+        } else if Ok(tpb.path.def) == dynsized_trait {
+            sizing = ImplicitSizing::None;
+        } else {
+            tcx.sess.span_warn(span,
+                               "default bound relaxed for a type parameter, but \
+                                this does nothing because the given bound is not \
+                                a default. Only `?Sized` and `?DynSized` are supported");
         }
-        _ if kind_id.is_ok() => {
-            return false;
-        }
-        // No lang item for Sized, so we can't add it as a bound.
-        None => {}
     }
 
-    true
+    sizing
 }
 
 /// Returns the early-bound lifetimes declared in this generics
@@ -1552,17 +1586,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-pub enum SizedByDefault { Yes, No, }
+#[derive(PartialEq, Eq)]
+enum SizedByDefault { Yes, No }
 
 /// Translate the AST's notion of ty param bounds (which are an enum consisting of a newtyped Ty or
 /// a region) to ty's notion of ty param bounds, which can either be user-defined traits, or the
 /// built-in trait (formerly known as kind): Send.
-pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
-                                        param_ty: Ty<'tcx>,
-                                        ast_bounds: &[hir::TyParamBound],
-                                        sized_by_default: SizedByDefault,
-                                        span: Span)
-                                        -> Bounds<'tcx>
+fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
+                                    param_ty: Ty<'tcx>,
+                                    ast_bounds: &[hir::TyParamBound],
+                                    sized_by_default: SizedByDefault,
+                                    span: Span) -> Bounds<'tcx>
 {
     let mut region_bounds = vec![];
     let mut trait_bounds = vec![];
@@ -1592,15 +1626,12 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
 
     trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
 
-    let implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
-        !is_unsized(astconv, ast_bounds, span)
-    } else {
-        false
-    };
+    let sizing = find_implicit_sizing(astconv, ast_bounds, span, sized_by_default);
 
     Bounds {
         region_bounds,
-        implicitly_sized,
+        implicitly_sized: sizing.implicitly_sized(),
+        implicitly_dynsized: sizing.implicitly_dynsized(),
         trait_bounds,
         projection_bounds,
     }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 9fc7e2c01aa19..1d03f73e0de51 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -256,6 +256,7 @@
 #![feature(core_float)]
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
+#![feature(dynsized)]
 #![feature(exact_size_is_empty)]
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs
index 97b09b7e2ad99..74228c0c2df3c 100644
--- a/src/libstd/panic.rs
+++ b/src/libstd/panic.rs
@@ -22,6 +22,12 @@ use rc::Rc;
 use sync::{Arc, Mutex, RwLock, atomic};
 use thread::Result;
 
+#[cfg(stage0)]
+use core::marker::Sized as DynSized;
+
+#[cfg(not(stage0))]
+use core::marker::DynSized;
+
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub use panicking::{take_hook, set_hook, PanicInfo, Location};
 
@@ -101,6 +107,14 @@ pub use panicking::{take_hook, set_hook, PanicInfo, Location};
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 #[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
                             across an unwind boundary"]
+#[cfg(not(stage0))]
+pub trait UnwindSafe: ?DynSized {}
+
+/// docs
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[rustc_on_unimplemented = "the type {Self} may not be safely transferred \
+                            across an unwind boundary"]
+#[cfg(stage0)]
 pub trait UnwindSafe {}
 
 /// A marker trait representing types where a shared reference is considered
@@ -115,6 +129,15 @@ pub trait UnwindSafe {}
 #[rustc_on_unimplemented = "the type {Self} may contain interior mutability \
                             and a reference may not be safely transferrable \
                             across a catch_unwind boundary"]
+#[cfg(not(stage0))]
+pub trait RefUnwindSafe: ?DynSized {}
+
+/// docs
+#[stable(feature = "catch_unwind", since = "1.9.0")]
+#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \
+                            and a reference may not be safely transferrable \
+                            across a catch_unwind boundary"]
+#[cfg(stage0)]
 pub trait RefUnwindSafe {}
 
 /// A simple wrapper around a type to assert that it is unwind safe.
@@ -190,13 +213,13 @@ pub struct AssertUnwindSafe<T>(
 #[stable(feature = "catch_unwind", since = "1.9.0")]
 impl UnwindSafe for .. {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<'a, T: ?Sized> !UnwindSafe for &'a mut T {}
+impl<'a, T: ?DynSized> !UnwindSafe for &'a mut T {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<'a, T: RefUnwindSafe + ?Sized> UnwindSafe for &'a T {}
+impl<'a, T: RefUnwindSafe + ?DynSized> UnwindSafe for &'a T {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *const T {}
+impl<T: RefUnwindSafe + ?DynSized> UnwindSafe for *const T {}
 #[stable(feature = "catch_unwind", since = "1.9.0")]
-impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
+impl<T: RefUnwindSafe + ?DynSized> UnwindSafe for *mut T {}
 #[unstable(feature = "unique", issue = "27730")]
 impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
 #[unstable(feature = "shared", issue = "27730")]

From 2d3e2b575d5a2bec4129b5b57553426acd3cea12 Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Fri, 8 Sep 2017 19:55:10 +0200
Subject: [PATCH 4/7] Make <*const T>::is_null() and al work with T: ?DynSized.

---
 src/libcore/ptr.rs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 60ff90de77bfa..3e108c93c194d 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -27,6 +27,11 @@ use nonzero::NonZero;
 
 use cmp::Ordering::{self, Less, Equal, Greater};
 
+#[cfg(stage0)]
+use marker::Sized as DynSized;
+#[cfg(not(stage0))]
+use marker::DynSized;
+
 // FIXME #19649: intrinsic docs don't render, so these have no docs :(
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -473,7 +478,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
 }
 
 #[lang = "const_ptr"]
-impl<T: ?Sized> *const T {
+impl<T: ?DynSized> *const T {
     /// Returns `true` if the pointer is null.
     ///
     /// # Examples
@@ -1105,7 +1110,7 @@ impl<T: ?Sized> *const T {
 }
 
 #[lang = "mut_ptr"]
-impl<T: ?Sized> *mut T {
+impl<T: ?DynSized> *mut T {
     /// Returns `true` if the pointer is null.
     ///
     /// # Examples

From 1eefab4ba0d5a4c2c325bd5de988d05353a9d87e Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Fri, 8 Sep 2017 14:42:59 +0200
Subject: [PATCH 5/7] Fix tests for DynSized

---
 .../auxiliary/tdticc_coherence_lib.rs         |  6 ++--
 .../extern-types-not-sync-send.rs             |  8 +++--
 src/test/compile-fail/extern-types-unsized.rs | 23 +++---------
 src/test/compile-fail/maybe-bounds.rs         |  9 +++--
 src/test/compile-fail/phantom-oibit.rs        |  6 ++--
 src/test/compile-fail/privacy-sanity.rs       | 10 +++---
 ...-default-trait-impl-constituent-types-2.rs |  6 ++--
 ...ck-default-trait-impl-constituent-types.rs |  6 ++--
 .../typeck-default-trait-impl-negation.rs     |  8 +++--
 .../typeck-default-trait-impl-precedence.rs   |  6 ++--
 .../run-pass/extern-types-manual-sync-send.rs |  8 +++--
 .../run-pass/extern-types-pointer-cast.rs     | 13 -------
 src/test/run-pass/extern-types-size_of_val.rs | 26 --------------
 .../run-pass/extern-types-thin-pointer.rs     | 35 +++++--------------
 src/test/run-pass/issue-29516.rs              |  6 ++--
 .../ui/on-unimplemented/multiple-impls.stderr | 26 +-------------
 src/test/ui/on-unimplemented/on-impl.stderr   | 10 +-----
 17 files changed, 66 insertions(+), 146 deletions(-)
 delete mode 100644 src/test/run-pass/extern-types-size_of_val.rs

diff --git a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs
index 2e425ac96c55f..a2389c9b0d7fb 100644
--- a/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs
+++ b/src/test/compile-fail/auxiliary/tdticc_coherence_lib.rs
@@ -8,10 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits, core)]
+#![feature(dynsized, optin_builtin_traits)]
 #![crate_type = "rlib"]
 
-pub trait DefaultedTrait { }
+use std::marker::DynSized;
+
+pub trait DefaultedTrait: ?DynSized { }
 impl DefaultedTrait for .. { }
 
 pub struct Something<T> { t: T }
diff --git a/src/test/compile-fail/extern-types-not-sync-send.rs b/src/test/compile-fail/extern-types-not-sync-send.rs
index 2f00cf812e473..4e19215f0c513 100644
--- a/src/test/compile-fail/extern-types-not-sync-send.rs
+++ b/src/test/compile-fail/extern-types-not-sync-send.rs
@@ -10,14 +10,16 @@
 
 // Make sure extern types are !Sync and !Send.
 
-#![feature(extern_types)]
+#![feature(dynsized, extern_types)]
+
+use std::marker::DynSized;
 
 extern {
     type A;
 }
 
-fn assert_sync<T: ?Sized + Sync>() { }
-fn assert_send<T: ?Sized + Send>() { }
+fn assert_sync<T: ?DynSized + Sync>() { }
+fn assert_send<T: ?DynSized + Send>() { }
 
 fn main() {
     assert_sync::<A>();
diff --git a/src/test/compile-fail/extern-types-unsized.rs b/src/test/compile-fail/extern-types-unsized.rs
index faa27894806f8..8a8df73171645 100644
--- a/src/test/compile-fail/extern-types-unsized.rs
+++ b/src/test/compile-fail/extern-types-unsized.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Make sure extern types are !Sized.
+// Make sure extern types are !Sized and !DynSized.
 
 #![feature(extern_types)]
 
@@ -16,28 +16,13 @@ extern {
     type A;
 }
 
-struct Foo {
-    x: u8,
-    tail: A,
-}
-
-struct Bar<T: ?Sized> {
-    x: u8,
-    tail: T,
-}
-
 fn assert_sized<T>() { }
+fn assert_dynsized<T: ?Sized>() { }
 
 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
+    assert_dynsized::<A>();
+    //~^ ERROR the trait bound `A: std::marker::DynSized` is not satisfied
 }
diff --git a/src/test/compile-fail/maybe-bounds.rs b/src/test/compile-fail/maybe-bounds.rs
index b0b412bbf89ec..743d636e4d94a 100644
--- a/src/test/compile-fail/maybe-bounds.rs
+++ b/src/test/compile-fail/maybe-bounds.rs
@@ -8,10 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+trait Tr: ?Sized {} //~ ERROR `?Sized` is not permitted in supertraits
                     //~^ NOTE traits are `?Sized` by default
 
 type A1 = Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types
-type A2 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types
+type A2 = Tr + ?DynSized; //~ ERROR `?Trait` is not permitted in trait object types
+type A3 = for<'a> Tr + ?Sized; //~ ERROR `?Trait` is not permitted in trait object types
 
 fn main() {}
diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs
index c84927ea26639..08d4460a364d1 100644
--- a/src/test/compile-fail/phantom-oibit.rs
+++ b/src/test/compile-fail/phantom-oibit.rs
@@ -12,11 +12,11 @@
 // the `PhantomData<T>` type itself (which almost always implements a "default" trait
 // (`impl Trait for ..`))
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-use std::marker::{PhantomData};
+use std::marker::{DynSized, PhantomData};
 
-unsafe trait Zen {}
+unsafe trait Zen: ?DynSized {}
 
 unsafe impl Zen for .. {}
 
diff --git a/src/test/compile-fail/privacy-sanity.rs b/src/test/compile-fail/privacy-sanity.rs
index 933ec3837dfc7..5977068756bed 100644
--- a/src/test/compile-fail/privacy-sanity.rs
+++ b/src/test/compile-fail/privacy-sanity.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait MarkerTr {}
+use std::marker::DynSized;
+
+trait MarkerTr: ?DynSized {}
 pub trait Tr {
     fn f();
     const C: u8;
@@ -38,7 +40,7 @@ pub extern "C" { //~ ERROR unnecessary visibility qualifier
 }
 
 const MAIN: u8 = {
-    trait MarkerTr {}
+    trait MarkerTr: ?DynSized {}
     pub trait Tr {
         fn f();
         const C: u8;
@@ -69,7 +71,7 @@ const MAIN: u8 = {
 };
 
 fn main() {
-    trait MarkerTr {}
+    trait MarkerTr: ?DynSized {}
     pub trait Tr {
         fn f();
         const C: u8;
diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs
index 8a46d6c76c30f..a8ae32421002e 100644
--- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs
+++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait MyTrait {}
+use std::marker::DynSized;
+
+trait MyTrait: ?DynSized {}
 
 impl MyTrait for .. {}
 
diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs
index 3d7746b369cc0..fc3efdf9a7893 100644
--- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs
+++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait MyTrait {}
+use std::marker::DynSized;
+
+trait MyTrait: ?DynSized {}
 
 impl MyTrait for .. {}
 impl<T> !MyTrait for *mut T {}
diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs
index 8c2658b89a506..feb97ce453ec9 100644
--- a/src/test/compile-fail/typeck-default-trait-impl-negation.rs
+++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs
@@ -8,13 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait MyTrait {}
+use std::marker::DynSized;
+
+trait MyTrait: ?DynSized {}
 
 impl MyTrait for .. {}
 
-unsafe trait MyUnsafeTrait {}
+unsafe trait MyUnsafeTrait: ?DynSized {}
 
 unsafe impl MyUnsafeTrait for .. {}
 
diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs
index 66c7a1c75ffe4..506a6a2b35c8f 100644
--- a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs
+++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs
@@ -13,9 +13,11 @@
 // other words, the `..` impl only applies if there are no existing
 // impls whose types unify.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait Defaulted { }
+use std::marker::DynSized;
+
+trait Defaulted: ?DynSized { }
 impl Defaulted for .. { }
 impl<'a,T:Signed> Defaulted for &'a T { }
 impl<'a,T:Signed> Defaulted for &'a mut T { }
diff --git a/src/test/run-pass/extern-types-manual-sync-send.rs b/src/test/run-pass/extern-types-manual-sync-send.rs
index c6530c3ea773a..113a02072b179 100644
--- a/src/test/run-pass/extern-types-manual-sync-send.rs
+++ b/src/test/run-pass/extern-types-manual-sync-send.rs
@@ -10,7 +10,9 @@
 
 // Test that unsafe impl for Sync/Send can be provided for extern types.
 
-#![feature(extern_types)]
+#![feature(dynsized, extern_types)]
+
+use std::marker::DynSized;
 
 extern {
     type A;
@@ -19,8 +21,8 @@ extern {
 unsafe impl Sync for A { }
 unsafe impl Send for A { }
 
-fn assert_sync<T: ?Sized + Sync>() { }
-fn assert_send<T: ?Sized + Send>() { }
+fn assert_sync<T: ?DynSized + Sync>() { }
+fn assert_send<T: ?DynSized + Send>() { }
 
 fn main() {
     assert_sync::<A>();
diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs
index 628a570665a33..b53f98aa79a5a 100644
--- a/src/test/run-pass/extern-types-pointer-cast.rs
+++ b/src/test/run-pass/extern-types-pointer-cast.rs
@@ -17,16 +17,6 @@ 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")]
@@ -34,7 +24,4 @@ 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
deleted file mode 100644
index 0aabce99debe8..0000000000000
--- a/src/test/run-pass/extern-types-size_of_val.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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
index c2444a58b5a1b..477066585d256 100644
--- a/src/test/run-pass/extern-types-thin-pointer.rs
+++ b/src/test/run-pass/extern-types-thin-pointer.rs
@@ -19,33 +19,16 @@ 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 ()>());
+fn main() {
+    assert_eq!(size_of::<*const A>(), size_of::<*const ()>());
+    assert_eq!(align_of::<*const A>(), align_of::<*const ()>());
 
-    assert_eq!(size_of::<&T>(), size_of::<&()>());
-    assert_eq!(align_of::<&T>(), align_of::<&()>());
+    assert_eq!(size_of::<*mut A>(), size_of::<*mut ()>());
+    assert_eq!(align_of::<*mut A>(), align_of::<*mut ()>());
 
-    assert_eq!(size_of::<&mut T>(), size_of::<&mut ()>());
-    assert_eq!(align_of::<&mut T>(), align_of::<&mut ()>());
-}
+    assert_eq!(size_of::<&A>(), size_of::<&()>());
+    assert_eq!(align_of::<&A>(), align_of::<&()>());
 
-fn main() {
-    assert_thin::<A>();
-    assert_thin::<Foo>();
-    assert_thin::<Bar<A>>();
-    assert_thin::<Bar<Bar<A>>>();
+    assert_eq!(size_of::<&mut A>(), size_of::<&mut ()>());
+    assert_eq!(align_of::<&mut A>(), align_of::<&mut ()>());
 }
diff --git a/src/test/run-pass/issue-29516.rs b/src/test/run-pass/issue-29516.rs
index b586abc29e243..8d76112ecde03 100644
--- a/src/test/run-pass/issue-29516.rs
+++ b/src/test/run-pass/issue-29516.rs
@@ -8,9 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(optin_builtin_traits)]
+#![feature(dynsized, optin_builtin_traits)]
 
-trait NotSame {}
+use std::marker::DynSized;
+
+trait NotSame: ?DynSized {}
 impl NotSame for .. {}
 impl<A> !NotSame for (A, A) {}
 
diff --git a/src/test/ui/on-unimplemented/multiple-impls.stderr b/src/test/ui/on-unimplemented/multiple-impls.stderr
index a1fa8b720a829..d377f46547f48 100644
--- a/src/test/ui/on-unimplemented/multiple-impls.stderr
+++ b/src/test/ui/on-unimplemented/multiple-impls.stderr
@@ -7,14 +7,6 @@ error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
    = help: the trait `Index<u32>` is not implemented for `[i32]`
    = note: required by `Index::index`
 
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
-  --> $DIR/multiple-impls.rs:43:5
-   |
-43 |     Index::index(&[] as &[i32], 2u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message
-   |
-   = help: the trait `Index<u32>` is not implemented for `[i32]`
-
 error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
   --> $DIR/multiple-impls.rs:49:5
    |
@@ -24,14 +16,6 @@ error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
    = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
    = note: required by `Index::index`
 
-error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:49:5
-   |
-49 |     Index::index(&[] as &[i32], Foo(2u32));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo
-   |
-   = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
-
 error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
   --> $DIR/multiple-impls.rs:55:5
    |
@@ -41,13 +25,5 @@ error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
    = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
    = note: required by `Index::index`
 
-error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
-  --> $DIR/multiple-impls.rs:55:5
-   |
-55 |     Index::index(&[] as &[i32], Bar(2u32));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar
-   |
-   = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/on-unimplemented/on-impl.stderr b/src/test/ui/on-unimplemented/on-impl.stderr
index c8c06bf44fd6f..d3edc9dde8033 100644
--- a/src/test/ui/on-unimplemented/on-impl.stderr
+++ b/src/test/ui/on-unimplemented/on-impl.stderr
@@ -7,13 +7,5 @@ error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
    = help: the trait `Index<u32>` is not implemented for `[i32]`
    = note: required by `Index::index`
 
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
-  --> $DIR/on-impl.rs:32:5
-   |
-32 |     Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
-   |
-   = help: the trait `Index<u32>` is not implemented for `[i32]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 

From d51764d04739cf718f32322a524019d37460f542 Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Fri, 8 Sep 2017 19:28:21 +0200
Subject: [PATCH 6/7] Add DynSized related tests

---
 .../compile-fail/dynsized/no-manual-impl.rs   | 25 +++++++++++++
 src/test/compile-fail/dynsized/size_of_val.rs | 29 +++++++++++++++
 .../dynsized/struct-last-field.rs             | 36 +++++++++++++++++++
 .../dynsized/supertait-unbound.rs             | 28 +++++++++++++++
 .../compile-fail/dynsized/tuple-last-field.rs | 28 +++++++++++++++
 .../dynsized/sized-implies-dynsized.rs        | 26 ++++++++++++++
 .../run-pass/dynsized/supertrait-default.rs   | 27 ++++++++++++++
 7 files changed, 199 insertions(+)
 create mode 100644 src/test/compile-fail/dynsized/no-manual-impl.rs
 create mode 100644 src/test/compile-fail/dynsized/size_of_val.rs
 create mode 100644 src/test/compile-fail/dynsized/struct-last-field.rs
 create mode 100644 src/test/compile-fail/dynsized/supertait-unbound.rs
 create mode 100644 src/test/compile-fail/dynsized/tuple-last-field.rs
 create mode 100644 src/test/run-pass/dynsized/sized-implies-dynsized.rs
 create mode 100644 src/test/run-pass/dynsized/supertrait-default.rs

diff --git a/src/test/compile-fail/dynsized/no-manual-impl.rs b/src/test/compile-fail/dynsized/no-manual-impl.rs
new file mode 100644
index 0000000000000..b591bc49246c1
--- /dev/null
+++ b/src/test/compile-fail/dynsized/no-manual-impl.rs
@@ -0,0 +1,25 @@
+// 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 DynSized cannot be implemented manually.
+
+#![feature(extern_types)]
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+extern {
+    type foo;
+}
+
+impl DynSized for foo { }
+//~^ ERROR explicit impls for the `DynSized` trait are not permitted
+
+fn main() { }
diff --git a/src/test/compile-fail/dynsized/size_of_val.rs b/src/test/compile-fail/dynsized/size_of_val.rs
new file mode 100644
index 0000000000000..756372978360e
--- /dev/null
+++ b/src/test/compile-fail/dynsized/size_of_val.rs
@@ -0,0 +1,29 @@
+// 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.
+
+// Ensure `size_of_val` / `align_of_val` can't be used on !DynSized types
+
+#![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)
+    };
+
+    size_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied
+
+    align_of_val(x); //~ERROR the trait bound `A: std::marker::DynSized` is not satisfied
+}
diff --git a/src/test/compile-fail/dynsized/struct-last-field.rs b/src/test/compile-fail/dynsized/struct-last-field.rs
new file mode 100644
index 0000000000000..de27126748855
--- /dev/null
+++ b/src/test/compile-fail/dynsized/struct-last-field.rs
@@ -0,0 +1,36 @@
+// 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.
+
+// Ensure !DynSized fields can't be used in structs, even as the last field.
+
+#![feature(extern_types)]
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+extern {
+    type foo;
+}
+
+struct A {
+    x: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied
+}
+
+struct B {
+    x: usize,
+    y: foo, //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied
+}
+
+struct C<T: ?DynSized> {
+    x: usize,
+    y: T, //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/dynsized/supertait-unbound.rs b/src/test/compile-fail/dynsized/supertait-unbound.rs
new file mode 100644
index 0000000000000..e4d6ae3cbf213
--- /dev/null
+++ b/src/test/compile-fail/dynsized/supertait-unbound.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 traits can opt-out of being DynSized by default.
+// See also run-pass/dynsized/supertrait-default.rs
+
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+fn assert_dynsized<T: ?Sized>() { }
+
+trait Tr: ?DynSized {
+    fn foo() {
+        assert_dynsized::<Self>();
+        //~^ ERROR the trait bound `Self: std::marker::DynSized` is not satisfied
+    }
+}
+
+fn main() { }
+
diff --git a/src/test/compile-fail/dynsized/tuple-last-field.rs b/src/test/compile-fail/dynsized/tuple-last-field.rs
new file mode 100644
index 0000000000000..df86a100f90b4
--- /dev/null
+++ b/src/test/compile-fail/dynsized/tuple-last-field.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.
+
+// Ensure !DynSized fields can't be used in tuples, even as the last field.
+
+#![feature(extern_types)]
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+extern {
+    type foo;
+}
+
+fn baz<T: ?DynSized>() {
+    let x: &(u8, foo); //~ERROR the trait bound `foo: std::marker::DynSized` is not satisfied
+
+    let y: &(u8, T); //~ERROR the trait bound `T: std::marker::DynSized` is not satisfied
+}
+
+fn main() { }
diff --git a/src/test/run-pass/dynsized/sized-implies-dynsized.rs b/src/test/run-pass/dynsized/sized-implies-dynsized.rs
new file mode 100644
index 0000000000000..9aa61b4e6b595
--- /dev/null
+++ b/src/test/run-pass/dynsized/sized-implies-dynsized.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(dynsized)]
+
+use std::marker::DynSized;
+
+fn foo<T: ?DynSized>() {
+}
+
+fn bar<T: ?Sized>() {
+    foo::<T>();
+}
+
+fn baz<T>() {
+    bar::<T>();
+}
+
+fn main() { }
diff --git a/src/test/run-pass/dynsized/supertrait-default.rs b/src/test/run-pass/dynsized/supertrait-default.rs
new file mode 100644
index 0000000000000..dabc76112fe07
--- /dev/null
+++ b/src/test/run-pass/dynsized/supertrait-default.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 traits have DynSized as a super trait by default.
+// See also compile-fail/dynsized/supertrait-unbound.rs
+
+#![feature(dynsized)]
+
+use std::marker::DynSized;
+
+fn assert_dynsized<T: ?Sized>() { }
+
+trait Tr {
+    fn foo() {
+        assert_dynsized::<Self>();
+    }
+}
+
+fn main() { }
+

From 55c2522b262c2672989e37c29ede4dc6b3ed64ac Mon Sep 17 00:00:00 2001
From: Paul Lietar <paul@lietar.net>
Date: Fri, 29 Sep 2017 20:50:57 +0200
Subject: [PATCH 7/7] Fix tidy errors

---
 src/librustc/util/ppaux.rs            | 6 ++++--
 src/librustc_passes/ast_validation.rs | 3 ++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 4fd988839701e..ff2c00aa43e24 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -815,11 +815,13 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     write!(f, "impl")?;
                     for predicate in bounds.predicates {
                         if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() {
+                            let did = trait_ref.def_id();
+
                             // Don't print +Sized/DynSized, but rather +?Sized/DynSized if absent.
-                            if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() {
+                            if Some(did) == tcx.lang_items().sized_trait() {
                                 is_sized = true;
                                 continue;
-                            } else if Some(trait_ref.def_id()) == tcx.lang_items().dynsized_trait() {
+                            } else if Some(did) == tcx.lang_items().dynsized_trait() {
                                 is_dynsized = true;
                                 continue;
                             }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 0e6be49a7cd97..36f71025ea3dc 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -152,7 +152,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                             any_lifetime_bounds = true;
                         }
                         TraitTyParamBound(ref poly, TraitBoundModifier::Maybe) => {
-                            self.session.span_err(poly.span, "`?Trait` is not permitted in trait object types");
+                            self.session.span_err(poly.span,
+                                "`?Trait` is not permitted in trait object types");
                         }
                         _ => (),
                     }