about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-04-03 13:38:45 +1300
committerNick Cameron <ncameron@mozilla.com>2014-04-23 12:30:58 +1200
commitf78add10cde772b9d743a84a604dc584b63a06fc (patch)
treebc159ccd2a18de0a71e4163e48b64cc31ae9dbcb
parentc3b2f2b0c6f074fb98add56a1977d407e294c9ed (diff)
downloadrust-f78add10cde772b9d743a84a604dc584b63a06fc.tar.gz
rust-f78add10cde772b9d743a84a604dc584b63a06fc.zip
Support unsized types with the `type` keyword
-rw-r--r--src/librustc/front/config.rs4
-rw-r--r--src/librustc/metadata/common.rs1
-rw-r--r--src/librustc/metadata/decoder.rs21
-rw-r--r--src/librustc/metadata/encoder.rs15
-rw-r--r--src/librustc/middle/privacy.rs8
-rw-r--r--src/librustc/middle/resolve.rs7
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc/middle/ty.rs26
-rw-r--r--src/librustc/middle/typeck/check/mod.rs57
-rw-r--r--src/librustc/middle/typeck/collect.rs76
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs2
-rw-r--r--src/librustc/middle/typeck/variance.rs2
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/libsyntax/ast.rs9
-rw-r--r--src/libsyntax/ast_map.rs20
-rw-r--r--src/libsyntax/ext/build.rs3
-rw-r--r--src/libsyntax/ext/deriving/decodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/encodable.rs5
-rw-r--r--src/libsyntax/ext/deriving/generic.rs6
-rw-r--r--src/libsyntax/ext/deriving/hash.rs3
-rw-r--r--src/libsyntax/ext/deriving/rand.rs3
-rw-r--r--src/libsyntax/ext/deriving/ty.rs9
-rw-r--r--src/libsyntax/fold.rs4
-rw-r--r--src/libsyntax/parse/parser.rs27
-rw-r--r--src/libsyntax/print/pprust.rs8
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/compile-fail/bad-mid-path-type-params.rs3
-rw-r--r--src/test/compile-fail/borrowck-move-subcomponent.rs3
-rw-r--r--src/test/compile-fail/lint-dead-code-1.rs4
-rw-r--r--src/test/compile-fail/privacy1.rs3
-rw-r--r--src/test/compile-fail/unsized-bare-typaram.rs2
-rw-r--r--src/test/compile-fail/unsized-enum.rs2
-rw-r--r--src/test/compile-fail/unsized-struct.rs2
-rw-r--r--src/test/compile-fail/unsized.rs16
-rw-r--r--src/test/compile-fail/unsized2.rs17
-rw-r--r--src/test/compile-fail/unsized3.rs51
-rw-r--r--src/test/compile-fail/unsized4.rs19
-rw-r--r--src/test/run-pass/unsized.rs26
-rw-r--r--src/test/run-pass/unsized2.rs82
39 files changed, 484 insertions, 73 deletions
diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs
index e630d7e15e0..b8f20b5e439 100644
--- a/src/librustc/front/config.rs
+++ b/src/librustc/front/config.rs
@@ -103,12 +103,12 @@ fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
                 .map(|x| *x).collect();
             ast::ItemImpl((*a).clone(), (*b).clone(), c, methods)
         }
-        ast::ItemTrait(ref a, ref b, ref methods) => {
+        ast::ItemTrait(ref a, b, ref c, ref methods) => {
             let methods = methods.iter()
                                  .filter(|m| trait_method_in_cfg(cx, *m) )
                                  .map(|x| (*x).clone())
                                  .collect();
-            ast::ItemTrait((*a).clone(), (*b).clone(), methods)
+            ast::ItemTrait((*a).clone(), b, (*c).clone(), methods)
         }
         ast::ItemStruct(def, ref generics) => {
             ast::ItemStruct(fold_struct(cx, def), generics.clone())
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 4a0b3ea0cf6..0ea6598a99f 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -170,6 +170,7 @@ pub static tag_lang_items_item_node_id: uint = 0x73;
 
 pub static tag_item_unnamed_field: uint = 0x74;
 pub static tag_items_data_item_visibility: uint = 0x76;
+pub static tag_items_data_item_sized: uint = 0x77;
 
 pub static tag_item_method_tps: uint = 0x79;
 pub static tag_item_method_fty: uint = 0x7a;
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 37d9d3417c9..b76b6d0c380 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -164,6 +164,19 @@ fn item_visibility(item: ebml::Doc) -> ast::Visibility {
     }
 }
 
+fn item_sized(item: ebml::Doc) -> ast::Sized {
+    match reader::maybe_get_doc(item, tag_items_data_item_sized) {
+        None => ast::StaticSize,
+        Some(sized_doc) => {
+            match reader::doc_as_u8(sized_doc) as char {
+                'd' => ast::DynSize,
+                's' => ast::StaticSize,
+                _ => fail!("unknown sized-ness character")
+            }
+        }
+    }
+}
+
 fn item_method_sort(item: ebml::Doc) -> char {
     let mut ret = 'r';
     reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
@@ -371,6 +384,7 @@ pub fn get_trait_def(cdata: Cmd,
     let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
                                      tag_items_data_item_ty_param_bounds);
     let rp_defs = item_region_param_defs(item_doc, cdata);
+    let sized = item_sized(item_doc);
     let mut bounds = ty::EmptyBuiltinBounds();
     // Collect the builtin bounds from the encoded supertraits.
     // FIXME(#8559): They should be encoded directly.
@@ -382,6 +396,13 @@ pub fn get_trait_def(cdata: Cmd,
         });
         true
     });
+    // Turn sized into a bound, FIXME(#8559).
+    if sized == ast::StaticSize {
+        tcx.lang_items.to_builtin_kind(tcx.lang_items.sized_trait().unwrap()).map(|bound| {
+            bounds.add(bound);
+        });
+    }
+
     ty::TraitDef {
         generics: ty::Generics {type_param_defs: tp_defs,
                                 region_param_defs: rp_defs},
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 848fd8d362e..d5ee1b15ae2 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -832,6 +832,16 @@ fn encode_extension_implementations(ecx: &EncodeContext,
     }
 }
 
+fn encode_sized(ebml_w: &mut Encoder, sized: Sized) {
+    ebml_w.start_tag(tag_items_data_item_sized);
+    let ch = match sized {
+        DynSize => 'd',
+        StaticSize => 's',
+    };
+    ebml_w.wr_str(str::from_char(ch));
+    ebml_w.end_tag();
+}
+
 fn encode_info_for_item(ecx: &EncodeContext,
                         ebml_w: &mut Encoder,
                         item: &Item,
@@ -1070,7 +1080,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
                                    ast_method)
         }
       }
-      ItemTrait(_, ref super_traits, ref ms) => {
+      ItemTrait(_, sized, ref super_traits, ref ms) => {
         add_to_index(item, ebml_w, index);
         ebml_w.start_tag(tag_items_data_item);
         encode_def_id(ebml_w, def_id);
@@ -1084,6 +1094,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_trait_ref(ebml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
         encode_name(ebml_w, item.ident.name);
         encode_attributes(ebml_w, item.attrs.as_slice());
+        // When we fix the rest of the supertrait nastiness (FIXME(#8559)), we
+        // should no longer need this ugly little hack either.
+        encode_sized(ebml_w, sized);
         encode_visibility(ebml_w, vis);
         for &method_def_id in ty::trait_method_def_ids(tcx, def_id).iter() {
             ebml_w.start_tag(tag_item_trait_method);
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index 427a7f406b0..eeccd1ca334 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -79,7 +79,7 @@ impl Visitor<()> for ParentVisitor {
             // method to the root. In this case, if the trait is private, then
             // parent all the methods to the trait to indicate that they're
             // private.
-            ast::ItemTrait(_, _, ref methods) if item.vis != ast::Public => {
+            ast::ItemTrait(_, _, _, ref methods) if item.vis != ast::Public => {
                 for m in methods.iter() {
                     match *m {
                         ast::Provided(ref m) => self.parents.insert(m.id, item.id),
@@ -274,7 +274,7 @@ impl<'a> Visitor<()> for EmbargoVisitor<'a> {
 
             // Default methods on traits are all public so long as the trait
             // is public
-            ast::ItemTrait(_, _, ref methods) if public_first => {
+            ast::ItemTrait(_, _, _, ref methods) if public_first => {
                 for method in methods.iter() {
                     match *method {
                         ast::Provided(ref m) => {
@@ -1082,7 +1082,7 @@ impl<'a> SanePrivacyVisitor<'a> {
                 }
             }
 
-            ast::ItemTrait(_, _, ref methods) => {
+            ast::ItemTrait(_, _, _, ref methods) => {
                 for m in methods.iter() {
                     match *m {
                         ast::Provided(ref m) => {
@@ -1142,7 +1142,7 @@ impl<'a> SanePrivacyVisitor<'a> {
 
             ast::ItemStruct(ref def, _) => check_struct(def),
 
-            ast::ItemTrait(_, _, ref methods) => {
+            ast::ItemTrait(_, _, _, ref methods) => {
                 for m in methods.iter() {
                     match *m {
                         ast::Required(..) => {}
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index d645b628aff..a2e6d6d1cab 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1325,7 +1325,7 @@ impl<'a> Resolver<'a> {
 
             ItemImpl(_, Some(_), _, _) => parent,
 
-            ItemTrait(_, _, ref methods) => {
+            ItemTrait(_, _, _, ref methods) => {
                 let name_bindings =
                     self.add_child(ident, parent.clone(), ForbidDuplicateTypes, sp);
 
@@ -3578,7 +3578,7 @@ impl<'a> Resolver<'a> {
                                             methods.as_slice());
             }
 
-            ItemTrait(ref generics, ref traits, ref methods) => {
+            ItemTrait(ref generics, _, ref traits, ref methods) => {
                 // Create a new rib for the self type.
                 let self_type_rib = Rib::new(NormalRibKind);
                 // plain insert (no renaming)
@@ -3786,9 +3786,8 @@ impl<'a> Resolver<'a> {
                 }
                 Some(declaration) => {
                     for argument in declaration.inputs.iter() {
-                        let binding_mode = ArgumentIrrefutableMode;
                         this.resolve_pattern(argument.pat,
-                                             binding_mode,
+                                             ArgumentIrrefutableMode,
                                              None);
 
                         this.resolve_type(argument.ty);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 130c93ac51e..88989f7ce08 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -84,7 +84,7 @@ impl<'a, 'b> Visitor<Scope<'a>> for LifetimeContext<'b> {
             ast::ItemEnum(_, ref generics) |
             ast::ItemStruct(_, ref generics) |
             ast::ItemImpl(ref generics, _, _, _) |
-            ast::ItemTrait(ref generics, _, _) => {
+            ast::ItemTrait(ref generics, _, _, _) => {
                 self.check_lifetime_names(&generics.lifetimes);
                 EarlyScope(0, &generics.lifetimes, &root)
             }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 9a3bdcc1e15..49968de28da 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2591,16 +2591,24 @@ pub fn type_is_machine(ty: t) -> bool {
 #[allow(dead_code)] // leaving in for DST
 pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
     match get(ty).sty {
-        // FIXME(#6308) add trait, vec, str, etc here.
-        ty_param(p) => {
+        ty_param(tp) => {
+            assert_eq!(tp.def_id.krate, ast::LOCAL_CRATE);
+
             let ty_param_defs = cx.ty_param_defs.borrow();
-            let param_def = ty_param_defs.get(&p.def_id.node);
-            if param_def.bounds.builtin_bounds.contains_elem(BoundSized) {
-                return true;
-            }
-            return false;
+            let param_def = ty_param_defs.get(&tp.def_id.node);
+            param_def.bounds.builtin_bounds.contains_elem(BoundSized)
         },
-        _ => return true,
+        ty_self(def_id) => {
+            let trait_def = lookup_trait_def(cx, def_id);
+            trait_def.bounds.contains_elem(BoundSized)
+        },
+        ty_struct(def_id, ref substs) => {
+            let flds = lookup_struct_fields(cx, def_id);
+            let mut tps = flds.iter().map(|f| lookup_field_type(cx, def_id, f.id, substs));
+            !tps.any(|ty| !type_is_sized(cx, ty))
+        }
+        ty_tup(ref ts) => !ts.iter().any(|t| !type_is_sized(cx, *t)),
+        _ => true
     }
 }
 
@@ -3495,7 +3503,7 @@ pub fn provided_trait_methods(cx: &ctxt, id: ast::DefId) -> Vec<Rc<Method>> {
         match cx.map.find(id.node) {
             Some(ast_map::NodeItem(item)) => {
                 match item.node {
-                    ItemTrait(_, _, ref ms) => {
+                    ItemTrait(_, _, _, ref ms) => {
                         let (_, p) = ast_util::split_trait_methods(ms.as_slice());
                         p.iter().map(|m| method(cx, ast_util::local_def(m.id))).collect()
                     }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index dc5b4f6d520..cd880f80817 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -369,21 +369,21 @@ impl<'a> GatherLocalsVisitor<'a> {
 }
 
 impl<'a> Visitor<()> for GatherLocalsVisitor<'a> {
-        // Add explicitly-declared locals.
+    // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &ast::Local, _: ()) {
-            let o_ty = match local.ty.node {
-              ast::TyInfer => None,
-              _ => Some(self.fcx.to_ty(local.ty))
-            };
-            self.assign(local.id, o_ty);
-            debug!("Local variable {} is assigned type {}",
-                   self.fcx.pat_to_str(local.pat),
-                   self.fcx.infcx().ty_to_str(
-                       self.fcx.inh.locals.borrow().get_copy(&local.id)));
-            visit::walk_local(self, local, ());
-
+        let o_ty = match local.ty.node {
+            ast::TyInfer => None,
+            _ => Some(self.fcx.to_ty(local.ty))
+        };
+        self.assign(local.id, o_ty);
+        debug!("Local variable {} is assigned type {}",
+               self.fcx.pat_to_str(local.pat),
+               self.fcx.infcx().ty_to_str(
+                   self.fcx.inh.locals.borrow().get_copy(&local.id)));
+        visit::walk_local(self, local, ());
     }
-        // Add pattern bindings.
+
+    // Add pattern bindings.
     fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
             match p.node {
               ast::PatIdent(_, ref path, _)
@@ -561,6 +561,26 @@ fn check_for_field_shadowing(tcx: &ty::ctxt,
     }
 }
 
+fn check_fields_sized(tcx: &ty::ctxt,
+                      id: ast::NodeId) {
+    let struct_def = tcx.map.expect_struct(id);
+    // FIXME(#13121) allow the last field to be DST
+    for f in struct_def.fields.iter() {
+        let t = ty::node_id_to_type(tcx, f.node.id);
+        if !ty::type_is_sized(tcx, t) {
+            match f.node.kind {
+                ast::NamedField(ident, _) => {
+                    tcx.sess.span_err(f.span, format!("Dynamically sized type in field {}",
+                                                      token::get_ident(ident)));
+                }
+                ast::UnnamedField(_) => {
+                    tcx.sess.span_err(f.span, "Dynamically sized type in field");
+                }
+            }
+        }
+    }
+}
+
 pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
     let tcx = ccx.tcx;
 
@@ -568,7 +588,10 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
     check_representable(tcx, span, id, "struct");
 
     // Check that the struct is instantiable
-    check_instantiable(tcx, span, id);
+    if check_instantiable(tcx, span, id) {
+        // This might cause stack overflow if id is not instantiable.
+        check_fields_sized(tcx, id);
+    }
 
     // Check there are no overlapping fields in super-structs
     check_for_field_shadowing(tcx, local_def(id));
@@ -630,7 +653,7 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
         }
 
       }
-      ast::ItemTrait(_, _, ref trait_methods) => {
+      ast::ItemTrait(_, _, _, ref trait_methods) => {
         let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
         for trait_method in (*trait_methods).iter() {
             match *trait_method {
@@ -3468,14 +3491,16 @@ pub fn check_representable(tcx: &ty::ctxt,
 /// is representable, but not instantiable.
 pub fn check_instantiable(tcx: &ty::ctxt,
                           sp: Span,
-                          item_id: ast::NodeId) {
+                          item_id: ast::NodeId) -> bool {
     let item_ty = ty::node_id_to_type(tcx, item_id);
     if !ty::is_instantiable(tcx, item_ty) {
         tcx.sess.span_err(sp, format!("this type cannot be instantiated \
                   without an instance of itself; \
                   consider using `Option<{}>`",
                                    ppaux::ty_to_str(tcx, item_ty)));
+        return false
     }
+    true
 }
 
 pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 0102001aa3c..0e1419dafa0 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -32,6 +32,7 @@ are represented as `ty_param()` instances.
 
 
 use metadata::csearch;
+use middle::lang_items::SizedTraitLangItem;
 use middle::resolve_lifetime;
 use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
 use middle::ty::{ty_param_bounds_and_ty};
@@ -189,7 +190,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
     match tcx.map.get(trait_id) {
         ast_map::NodeItem(item) => {
             match item.node {
-                ast::ItemTrait(ref generics, _, ref ms) => {
+                ast::ItemTrait(ref generics, _, _, ref ms) => {
                     let trait_ty_generics = ty_generics_for_type(ccx, generics);
 
                     // For each method, construct a suitable ty::Method and
@@ -402,7 +403,8 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, trait_id: ast::NodeId) {
 pub fn ensure_supertraits(ccx: &CrateCtxt,
                           id: ast::NodeId,
                           sp: codemap::Span,
-                          ast_trait_refs: &[ast::TraitRef])
+                          ast_trait_refs: &[ast::TraitRef],
+                          sized: ast::Sized)
                           -> ty::BuiltinBounds
 {
     let tcx = ccx.tcx;
@@ -433,6 +435,12 @@ pub fn ensure_supertraits(ccx: &CrateCtxt,
             }
         }
     }
+    if sized == ast::StaticSize {
+        match tcx.lang_items.require(SizedTraitLangItem) {
+            Ok(def_id) => { ty::try_add_builtin_trait(tcx, def_id, &mut bounds); },
+            Err(s) => tcx.sess.err(s),
+        };
+    }
 
     tcx.supertraits.borrow_mut().insert(local_def(id), Rc::new(ty_trait_refs));
     bounds
@@ -562,8 +570,7 @@ pub fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
         if ty_param.bounds.len() > 0 {
             ccx.tcx.sess.span_err(
                 span,
-                format!("trait bounds are not allowed in {} definitions",
-                     thing));
+                format!("trait bounds are not allowed in {} definitions", thing));
         }
     }
 }
@@ -634,7 +641,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
                 }
             }
         },
-        ast::ItemTrait(ref generics, _, ref trait_methods) => {
+        ast::ItemTrait(ref generics, _, _, ref trait_methods) => {
             let trait_def = trait_def_of_item(ccx, it);
 
             // Run convert_methods on the provided methods.
@@ -863,14 +870,15 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc<ty::TraitDef> {
     }
 
     match it.node {
-        ast::ItemTrait(ref generics, ref supertraits, _) => {
+        ast::ItemTrait(ref generics, sized, ref supertraits, _) => {
             let self_ty = ty::mk_self(tcx, def_id);
             let ty_generics = ty_generics_for_type(ccx, generics);
             let substs = mk_item_substs(ccx, &ty_generics, Some(self_ty));
             let bounds = ensure_supertraits(ccx,
                                             it.id,
                                             it.span,
-                                            supertraits.as_slice());
+                                            supertraits.as_slice(),
+                                            sized);
             let trait_def = Rc::new(ty::TraitDef {
                 generics: ty_generics,
                 bounds: bounds,
@@ -1032,7 +1040,12 @@ fn ty_generics(ccx: &CrateCtxt,
             existing_def_opt.unwrap_or_else(|| {
                 let param_ty = ty::param_ty {idx: base_index + offset,
                                              def_id: local_def(param.id)};
-                let bounds = Rc::new(compute_bounds(ccx, param_ty, &param.bounds));
+                let bounds = Rc::new(compute_bounds(ccx,
+                                                    param_ty,
+                                                    &param.bounds,
+                                                    param.sized,
+                                                    param.ident,
+                                                    param.span));
                 let default = param.default.map(|path| {
                     let ty = ast_ty_to_ty(ccx, &ExplicitRscope, path);
                     let cur_idx = param_ty.idx;
@@ -1067,7 +1080,10 @@ fn ty_generics(ccx: &CrateCtxt,
     fn compute_bounds(
         ccx: &CrateCtxt,
         param_ty: ty::param_ty,
-        ast_bounds: &OwnedSlice<ast::TyParamBound>) -> ty::ParamBounds
+        ast_bounds: &OwnedSlice<ast::TyParamBound>,
+        sized: ast::Sized,
+        ident: ast::Ident,
+        span: Span) -> ty::ParamBounds
     {
         /*!
          * Translate the AST's notion of ty param bounds (which are an
@@ -1086,9 +1102,8 @@ fn ty_generics(ccx: &CrateCtxt,
                     let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id);
                     let trait_ref = instantiate_trait_ref(ccx, b, ty);
                     if !ty::try_add_builtin_trait(
-                        ccx.tcx, trait_ref.def_id,
-                        &mut param_bounds.builtin_bounds)
-                    {
+                            ccx.tcx, trait_ref.def_id,
+                            &mut param_bounds.builtin_bounds) {
                         // Must be a user-defined trait
                         param_bounds.trait_bounds.push(trait_ref);
                     }
@@ -1100,8 +1115,45 @@ fn ty_generics(ccx: &CrateCtxt,
             }
         }
 
+        if sized == ast::StaticSize {
+            match ccx.tcx.lang_items.require(SizedTraitLangItem) {
+                Ok(def_id) => { ty::try_add_builtin_trait(ccx.tcx,
+                                                          def_id,
+                                                          &mut param_bounds.builtin_bounds); },
+                // Fixme(13367) after `type` makes it into the snapshot, we can check this properly
+                Err(_s) => {}, //ccx.tcx.sess.err(s),
+            }
+        }
+
+        check_bounds_compatible(ccx.tcx, &param_bounds, ident, span);
+
         param_bounds
     }
+
+    fn check_bounds_compatible(tcx: &ty::ctxt,
+                               param_bounds: &ty::ParamBounds,
+                               ident: ast::Ident,
+                               span: Span) {
+        // Currently the only bound which is incompatible with other bounds is
+        // Sized/Unsized.
+        if !param_bounds.builtin_bounds.contains_elem(ty::BoundSized) {
+            ty::each_bound_trait_and_supertraits(tcx,
+                                                 param_bounds.trait_bounds.as_slice(),
+                                                 |trait_ref| {
+                let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
+                for bound in trait_def.bounds.iter() {
+                    if bound == ty::BoundSized {
+                        tcx.sess.span_err(span,
+                            format!("incompatible bounds on type parameter {}, \
+                                     bound {} does not allow unsized type",
+                            token::get_ident(ident),
+                            ppaux::trait_ref_to_str(tcx, trait_ref)));
+                    }
+                }
+                true
+            });
+        }
+    }
 }
 
 pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index a5d41b15d5d..bb9c6a87bab 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -878,6 +878,8 @@ impl<'a> Rebuilder<'a> {
                 id: ty_param.id,
                 bounds: bounds,
                 default: ty_param.default,
+                span: ty_param.span,
+                sized: ty_param.sized,
             }
         })
     }
diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs
index 9e7c221d3c5..5485cddb476 100644
--- a/src/librustc/middle/typeck/variance.rs
+++ b/src/librustc/middle/typeck/variance.rs
@@ -347,7 +347,7 @@ impl<'a> Visitor<()> for TermsContext<'a> {
         match item.node {
             ast::ItemEnum(_, ref generics) |
             ast::ItemStruct(_, ref generics) |
-            ast::ItemTrait(ref generics, _, _) => {
+            ast::ItemTrait(ref generics, _, _, _) => {
                 for (i, p) in generics.lifetimes.iter().enumerate() {
                     self.add_inferred(item.id, RegionParam, i, p.id);
                 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 7de898a50a9..3fc65dd9647 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -261,7 +261,7 @@ impl<'a> RustdocVisitor<'a> {
                 };
                 om.statics.push(s);
             },
-            ast::ItemTrait(ref gen, ref tr, ref met) => {
+            ast::ItemTrait(ref gen, _, ref tr, ref met) => {
                 let t = Trait {
                     name: item.ident,
                     methods: met.iter().map(|x| (*x).clone()).collect(),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5d0b24fdb3e..97ddff78789 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -180,6 +180,7 @@ pub enum TyParamBound {
 pub struct TyParam {
     pub ident: Ident,
     pub id: NodeId,
+    pub sized: Sized,
     pub bounds: OwnedSlice<TyParamBound>,
     pub default: Option<P<Ty>>,
     pub span: Span
@@ -1052,6 +1053,12 @@ impl Visibility {
 }
 
 #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
+pub enum Sized {
+    DynSize,
+    StaticSize,
+}
+
+#[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
 pub struct StructField_ {
     pub kind: StructFieldKind,
     pub id: NodeId,
@@ -1109,7 +1116,7 @@ pub enum Item_ {
     ItemTy(P<Ty>, Generics),
     ItemEnum(EnumDef, Generics),
     ItemStruct(@StructDef, Generics),
-    ItemTrait(Generics, Vec<TraitRef> , Vec<TraitMethod> ),
+    ItemTrait(Generics, Sized, Vec<TraitRef> , Vec<TraitMethod> ),
     ItemImpl(Generics,
              Option<TraitRef>, // (optional) trait this impl implements
              P<Ty>, // self
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index 45954800e7e..d0e3ff4ae54 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -265,6 +265,24 @@ impl Map {
         }
     }
 
+    pub fn expect_struct(&self, id: NodeId) -> @StructDef {
+        match self.find(id) {
+            Some(NodeItem(i)) => {
+                match i.node {
+                    ItemStruct(struct_def, _) => struct_def,
+                    _ => fail!("struct ID bound to non-struct")
+                }
+            }
+            Some(NodeVariant(ref variant)) => {
+                match (*variant).node.kind {
+                    StructVariantKind(struct_def) => struct_def,
+                    _ => fail!("struct ID bound to enum variant that isn't struct-like"),
+                }
+            }
+            _ => fail!(format!("expected struct, found {}", self.node_to_str(id))),
+        }
+    }
+
     pub fn expect_foreign_item(&self, id: NodeId) -> @ForeignItem {
         match self.find(id) {
             Some(NodeForeignItem(item)) => item,
@@ -453,7 +471,7 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> {
                     None => {}
                 }
             }
-            ItemTrait(_, ref traits, ref methods) => {
+            ItemTrait(_, _, ref traits, ref methods) => {
                 for t in traits.iter() {
                     self.insert(t.ref_id, EntryItem(self.parent, i));
                 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index c1289ef9858..e1174ea6cc4 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -68,6 +68,7 @@ pub trait AstBuilder {
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               sized: ast::Sized,
                bounds: OwnedSlice<ast::TyParamBound>,
                default: Option<P<ast::Ty>>) -> ast::TyParam;
 
@@ -371,11 +372,13 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn typaram(&self,
                span: Span,
                id: ast::Ident,
+               sized: ast::Sized,
                bounds: OwnedSlice<ast::TyParamBound>,
                default: Option<P<ast::Ty>>) -> ast::TyParam {
         ast::TyParam {
             ident: id,
             id: ast::DUMMY_NODE_ID,
+            sized: sized,
             bounds: bounds,
             default: default,
             span: span
diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs
index 579de82c8db..35a1eb0bb83 100644
--- a/src/libsyntax/ext/deriving/decodable.rs
+++ b/src/libsyntax/ext/deriving/decodable.rs
@@ -13,6 +13,7 @@ The compiler code necessary for `#[deriving(Decodable)]`. See
 encodable.rs for more.
 */
 
+use ast;
 use ast::{MetaItem, Item, Expr, MutMutable, Ident};
 use codemap::Span;
 use ext::base::ExtCtxt;
@@ -35,10 +36,10 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds {
             lifetimes: Vec::new(),
-            bounds: vec!(("__D", vec!(Path::new_(
+            bounds: vec!(("__D", ast::StaticSize, vec!(Path::new_(
                             vec!("serialize", "Decoder"), None,
                             vec!(~Literal(Path::new_local("__E"))), true))),
-                         ("__E", vec!()))
+                         ("__E", ast::StaticSize, vec!()))
         },
         methods: vec!(
             MethodDef {
diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs
index 1c3edce96fb..806560f6826 100644
--- a/src/libsyntax/ext/deriving/encodable.rs
+++ b/src/libsyntax/ext/deriving/encodable.rs
@@ -82,6 +82,7 @@ would yield functions like:
 ```
 */
 
+use ast;
 use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil};
 use codemap::Span;
 use ext::base::ExtCtxt;
@@ -103,10 +104,10 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
         additional_bounds: Vec::new(),
         generics: LifetimeBounds {
             lifetimes: Vec::new(),
-            bounds: vec!(("__S", vec!(Path::new_(
+            bounds: vec!(("__S", ast::StaticSize, vec!(Path::new_(
                             vec!("serialize", "Encoder"), None,
                             vec!(~Literal(Path::new_local("__E"))), true))),
-                         ("__E", vec!()))
+                         ("__E", ast::StaticSize, vec!()))
         },
         methods: vec!(
             MethodDef {
diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs
index c040361a8eb..914451fb402 100644
--- a/src/libsyntax/ext/deriving/generic.rs
+++ b/src/libsyntax/ext/deriving/generic.rs
@@ -380,7 +380,11 @@ impl<'a> TraitDef<'a> {
             // require the current trait
             bounds.push(cx.typarambound(trait_path.clone()));
 
-            cx.typaram(self.span, ty_param.ident, OwnedSlice::from_vec(bounds), None)
+            cx.typaram(self.span,
+                       ty_param.ident,
+                       ty_param.sized,
+                       OwnedSlice::from_vec(bounds),
+                       None)
         }));
         let trait_generics = Generics {
             lifetimes: lifetimes,
diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs
index 23331dc03cb..d22027d203f 100644
--- a/src/libsyntax/ext/deriving/hash.rs
+++ b/src/libsyntax/ext/deriving/hash.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use ast;
 use ast::{MetaItem, Item, Expr, MutMutable};
 use codemap::Span;
 use ext::base::ExtCtxt;
@@ -25,7 +26,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt,
                     vec!(~Literal(Path::new_local("__S"))), true),
          LifetimeBounds {
              lifetimes: Vec::new(),
-             bounds: vec!(("__S", vec!(Path::new(vec!("std", "io", "Writer"))))),
+             bounds: vec!(("__S", ast::StaticSize, vec!(Path::new(vec!("std", "io", "Writer"))))),
          },
          Path::new_local("__S"))
     } else {
diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs
index 6b824e52bb3..e81aa55d10d 100644
--- a/src/libsyntax/ext/deriving/rand.rs
+++ b/src/libsyntax/ext/deriving/rand.rs
@@ -32,7 +32,8 @@ pub fn expand_deriving_rand(cx: &mut ExtCtxt,
                 generics: LifetimeBounds {
                     lifetimes: Vec::new(),
                     bounds: vec!(("R",
-                               vec!( Path::new(vec!("rand", "Rng")) )))
+                                  ast::StaticSize,
+                                  vec!( Path::new(vec!("rand", "Rng")) )))
                 },
                 explicit_self: None,
                 args: vec!(
diff --git a/src/libsyntax/ext/deriving/ty.rs b/src/libsyntax/ext/deriving/ty.rs
index a6bbad62b8e..6e3327b4039 100644
--- a/src/libsyntax/ext/deriving/ty.rs
+++ b/src/libsyntax/ext/deriving/ty.rs
@@ -186,14 +186,14 @@ impl<'a> Ty<'a> {
 }
 
 
-fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, bounds: &[Path],
+fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str, sized: ast::Sized, bounds: &[Path],
                self_ident: Ident, self_generics: &Generics) -> ast::TyParam {
     let bounds =
         bounds.iter().map(|b| {
             let path = b.to_path(cx, span, self_ident, self_generics);
             cx.typarambound(path)
         }).collect();
-    cx.typaram(span, cx.ident_of(name), bounds, None)
+    cx.typaram(span, cx.ident_of(name), sized, bounds, None)
 }
 
 fn mk_generics(lifetimes: Vec<ast::Lifetime> ,  ty_params: Vec<ast::TyParam> ) -> Generics {
@@ -206,7 +206,7 @@ fn mk_generics(lifetimes: Vec<ast::Lifetime> ,  ty_params: Vec<ast::TyParam> ) -
 /// Lifetimes and bounds on type parameters
 pub struct LifetimeBounds<'a> {
     pub lifetimes: Vec<&'a str>,
-    pub bounds: Vec<(&'a str, Vec<Path<'a>>)>,
+    pub bounds: Vec<(&'a str, ast::Sized, Vec<Path<'a>>)>,
 }
 
 impl<'a> LifetimeBounds<'a> {
@@ -226,10 +226,11 @@ impl<'a> LifetimeBounds<'a> {
         }).collect();
         let ty_params = self.bounds.iter().map(|t| {
             match t {
-                &(ref name, ref bounds) => {
+                &(ref name, sized, ref bounds) => {
                     mk_ty_param(cx,
                                 span,
                                 *name,
+                                sized,
                                 bounds.as_slice(),
                                 self_ty,
                                 self_generics)
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 72be633d456..04b289b9fca 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -447,6 +447,7 @@ pub fn fold_ty_param<T: Folder>(tp: &TyParam, fld: &mut T) -> TyParam {
     TyParam {
         ident: tp.ident,
         id: id,
+        sized: tp.sized,
         bounds: tp.bounds.map(|x| fold_ty_param_bound(x, fld)),
         default: tp.default.map(|x| fld.fold_ty(x)),
         span: tp.span
@@ -620,7 +621,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
                      methods.iter().map(|x| folder.fold_method(*x)).collect()
             )
         }
-        ItemTrait(ref generics, ref traits, ref methods) => {
+        ItemTrait(ref generics, ref sized, ref traits, ref methods) => {
             let methods = methods.iter().map(|method| {
                 match *method {
                     Required(ref m) => Required(folder.fold_type_method(m)),
@@ -628,6 +629,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: &Item_, folder: &mut T) -> Item_
                 }
             }).collect();
             ItemTrait(fold_generics(generics, folder),
+                      *sized,
                       traits.iter().map(|p| fold_trait_ref(p, folder)).collect(),
                       methods)
         }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 85480bebc90..8808312bed7 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -42,6 +42,7 @@ use ast::{PatIdent, PatLit, PatRange, PatRegion, PatStruct};
 use ast::{PatTup, PatUniq, PatWild, PatWildMulti};
 use ast::{BiRem, Required};
 use ast::{RetStyle, Return, BiShl, BiShr, Stmt, StmtDecl};
+use ast::{Sized, DynSize, StaticSize};
 use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
 use ast::{StructVariantKind, BiSub};
 use ast::StrStyle;
@@ -3390,10 +3391,11 @@ impl<'a> Parser<'a> {
         return (ret_lifetime, Some(OwnedSlice::from_vec(result)));
     }
 
-    // matches typaram = IDENT optbounds ( EQ ty )?
+    // matches typaram = type? IDENT optbounds ( EQ ty )?
     fn parse_ty_param(&mut self) -> TyParam {
-        let ident = self.parse_ident();
+        let sized = self.parse_sized();
         let span = self.span;
+        let ident = self.parse_ident();
         let (_, opt_bounds) = self.parse_optional_ty_param_bounds(false);
         // For typarams we don't care about the difference b/w "<T>" and "<T:>".
         let bounds = opt_bounds.unwrap_or_default();
@@ -3407,6 +3409,7 @@ impl<'a> Parser<'a> {
         TyParam {
             ident: ident,
             id: ast::DUMMY_NODE_ID,
+            sized: sized,
             bounds: bounds,
             default: default,
             span: span,
@@ -3797,6 +3800,7 @@ impl<'a> Parser<'a> {
     fn parse_item_trait(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
         let tps = self.parse_generics();
+        let sized = self.parse_for_sized();
 
         // Parse traits, if necessary.
         let traits;
@@ -3808,7 +3812,7 @@ impl<'a> Parser<'a> {
         }
 
         let meths = self.parse_trait_methods();
-        (ident, ItemTrait(tps, traits, meths), None)
+        (ident, ItemTrait(tps, sized, traits, meths), None)
     }
 
     // Parses two variants (with the region/type params always optional):
@@ -3999,6 +4003,23 @@ impl<'a> Parser<'a> {
         else { Inherited }
     }
 
+    fn parse_sized(&mut self) -> Sized {
+        if self.eat_keyword(keywords::Type) { DynSize }
+        else { StaticSize }
+    }
+
+    fn parse_for_sized(&mut self) -> Sized {
+        if self.eat_keyword(keywords::For) {
+            if !self.eat_keyword(keywords::Type) {
+                self.span_err(self.last_span,
+                    "expected 'type' after for in trait item");
+            }
+            DynSize
+        } else {
+            StaticSize
+        }
+    }
+
     // given a termination token and a vector of already-parsed
     // attributes (of length 0 or 1), parse all of the items in a module
     fn parse_mod_items(&mut self,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f4e337e2048..57438169d6d 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -673,10 +673,13 @@ impl<'a> State<'a> {
                 }
                 try!(self.bclose(item.span));
             }
-            ast::ItemTrait(ref generics, ref traits, ref methods) => {
+            ast::ItemTrait(ref generics, ref sized, ref traits, ref methods) => {
                 try!(self.head(visibility_qualified(item.vis, "trait")));
                 try!(self.print_ident(item.ident));
                 try!(self.print_generics(generics));
+                if *sized == ast::DynSize {
+                    try!(self.word_space("for type"));
+                }
                 if traits.len() != 0u {
                     try!(word(&mut self.s, ":"));
                     for (i, trait_) in traits.iter().enumerate() {
@@ -1910,6 +1913,9 @@ impl<'a> State<'a> {
                     } else {
                         let idx = idx - generics.lifetimes.len();
                         let param = generics.ty_params.get(idx);
+                        if param.sized == ast::DynSize {
+                            try!(s.word_space("type"));
+                        }
                         try!(s.print_ident(param.ident));
                         try!(s.print_bounds(&None, &param.bounds, false));
                         match param.default {
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 1f75c2e062f..e830daf8ede 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -257,7 +257,7 @@ pub fn walk_item<E: Clone, V: Visitor<E>>(visitor: &mut V, item: &Item, env: E)
                                      item.id,
                                      env)
         }
-        ItemTrait(ref generics, ref trait_paths, ref methods) => {
+        ItemTrait(ref generics, _, ref trait_paths, ref methods) => {
             visitor.visit_generics(generics, env.clone());
             for trait_path in trait_paths.iter() {
                 visitor.visit_path(&trait_path.path,
diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs
index 1b72e468428..58ed6624cbf 100644
--- a/src/test/compile-fail/bad-mid-path-type-params.rs
+++ b/src/test/compile-fail/bad-mid-path-type-params.rs
@@ -12,6 +12,9 @@
 
 #![no_std]
 
+#[lang="sized"]
+pub trait Sized {}
+
 struct S<T> {
     contents: T,
 }
diff --git a/src/test/compile-fail/borrowck-move-subcomponent.rs b/src/test/compile-fail/borrowck-move-subcomponent.rs
index f6ca6ac42b2..6940c85e0e6 100644
--- a/src/test/compile-fail/borrowck-move-subcomponent.rs
+++ b/src/test/compile-fail/borrowck-move-subcomponent.rs
@@ -13,6 +13,9 @@
 
 #![no_std]
 
+#[lang="sized"]
+pub trait Sized {}
+
 struct S {
   x : ~int
 }
diff --git a/src/test/compile-fail/lint-dead-code-1.rs b/src/test/compile-fail/lint-dead-code-1.rs
index 04326403376..bbcc59f0d6c 100644
--- a/src/test/compile-fail/lint-dead-code-1.rs
+++ b/src/test/compile-fail/lint-dead-code-1.rs
@@ -17,6 +17,10 @@
 #![crate_type="lib"]
 
 pub use foo2::Bar2;
+
+#[lang="sized"]
+pub trait Sized {}
+
 mod foo {
     pub struct Bar; //~ ERROR: code is never used
 }
diff --git a/src/test/compile-fail/privacy1.rs b/src/test/compile-fail/privacy1.rs
index 45d13bd7996..83141020b29 100644
--- a/src/test/compile-fail/privacy1.rs
+++ b/src/test/compile-fail/privacy1.rs
@@ -11,6 +11,9 @@
 #![feature(globs)]
 #![no_std] // makes debugging this test *a lot* easier (during resolve)
 
+#[lang="sized"]
+pub trait Sized {}
+
 mod bar {
     // shouln't bring in too much
     pub use self::glob::*;
diff --git a/src/test/compile-fail/unsized-bare-typaram.rs b/src/test/compile-fail/unsized-bare-typaram.rs
index ff9d379c30f..fd09d78a4fa 100644
--- a/src/test/compile-fail/unsized-bare-typaram.rs
+++ b/src/test/compile-fail/unsized-bare-typaram.rs
@@ -10,5 +10,5 @@
 
 // error-pattern: instantiating a type parameter with an incompatible type
 fn bar<T: Sized>() { }
-fn foo<T>() { bar::<T>() }
+fn foo<type T>() { bar::<T>() }
 fn main() { }
diff --git a/src/test/compile-fail/unsized-enum.rs b/src/test/compile-fail/unsized-enum.rs
index df7d82f0b25..f586fbb576b 100644
--- a/src/test/compile-fail/unsized-enum.rs
+++ b/src/test/compile-fail/unsized-enum.rs
@@ -10,5 +10,5 @@
 
 // error-pattern: instantiating a type parameter with an incompatible type
 fn bar<T: Sized>() { }
-fn foo<T>() { bar::<Option<T>>() }
+fn foo<type T>() { bar::<Option<T>>() }
 fn main() { }
diff --git a/src/test/compile-fail/unsized-struct.rs b/src/test/compile-fail/unsized-struct.rs
index da3e9e12430..9fab3accbb9 100644
--- a/src/test/compile-fail/unsized-struct.rs
+++ b/src/test/compile-fail/unsized-struct.rs
@@ -13,5 +13,5 @@
 struct Foo<T> { data: T }
 
 fn bar<T: Sized>() { }
-fn foo<T>() { bar::<Foo<T>>() }
+fn foo<type T>() { bar::<Foo<T>>() }
 fn main() { }
diff --git a/src/test/compile-fail/unsized.rs b/src/test/compile-fail/unsized.rs
new file mode 100644
index 00000000000..d5c2bbb21ca
--- /dev/null
+++ b/src/test/compile-fail/unsized.rs
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 syntax checks for `type` keyword.
+
+struct S1 for type; //~ ERROR expected `{`, `(`, or `;` after struct name but found `for`
+
+pub fn main() {
+}
diff --git a/src/test/compile-fail/unsized2.rs b/src/test/compile-fail/unsized2.rs
new file mode 100644
index 00000000000..0c9d05e2988
--- /dev/null
+++ b/src/test/compile-fail/unsized2.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 syntax checks for `type` keyword.
+
+fn f<X>() {}
+
+pub fn main() {
+    f<type>(); //~ ERROR found `type` in ident position
+}
diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs
new file mode 100644
index 00000000000..d842a289289
--- /dev/null
+++ b/src/test/compile-fail/unsized3.rs
@@ -0,0 +1,51 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 sized-ness checking in substitution.
+
+// Unbounded.
+fn f1<type X>(x: &X) {
+    f2::<X>(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n
+}
+fn f2<X>(x: &X) {
+}
+
+// Bounded.
+trait T for type {}
+fn f3<type X: T>(x: &X) {
+    f4::<X>(x); //~ ERROR instantiating a type parameter with an incompatible type `X`, which does n
+}
+fn f4<X: T>(x: &X) {
+}
+
+// I would like these to fail eventually.
+/*
+// impl - bounded
+trait T1<Z: T> {
+}
+struct S3<type Y>;
+impl<type X: T> T1<X> for S3<X> { //ERROR instantiating a type parameter with an incompatible type
+}
+
+// impl - unbounded
+trait T2<Z> {
+}
+impl<type X> T2<X> for S3<X> { //ERROR instantiating a type parameter with an incompatible type `X`
+
+// impl - struct
+trait T3<type Z> {
+}
+struct S4<Y>;
+impl<type X> T3<X> for S4<X> { //ERROR instantiating a type parameter with an incompatible type `X`
+}
+*/
+
+pub fn main() {
+}
diff --git a/src/test/compile-fail/unsized4.rs b/src/test/compile-fail/unsized4.rs
new file mode 100644
index 00000000000..968716320fd
--- /dev/null
+++ b/src/test/compile-fail/unsized4.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 bounds are sized-compatible.
+
+trait T {}
+fn f<type Y: T>() {
+//~^ERROR incompatible bounds on type parameter Y, bound T does not allow unsized type
+}
+
+pub fn main() {
+}
diff --git a/src/test/run-pass/unsized.rs b/src/test/run-pass/unsized.rs
new file mode 100644
index 00000000000..e7dadd4b5eb
--- /dev/null
+++ b/src/test/run-pass/unsized.rs
@@ -0,0 +1,26 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 syntax checks for `type` keyword.
+
+trait T1 for type {}
+pub trait T2 for type {}
+trait T3<X: T1> for type: T2 {}
+trait T4<type X> {}
+trait T5<type X, Y> {}
+trait T6<Y, type X> {}
+trait T7<type X, type Y> {}
+trait T8<type X: T2> {}
+struct S1<type X>;
+impl <type X> T1 for S1<X> {}
+fn f<type X>() {}
+
+pub fn main() {
+}
diff --git a/src/test/run-pass/unsized2.rs b/src/test/run-pass/unsized2.rs
new file mode 100644
index 00000000000..c8e8f98145f
--- /dev/null
+++ b/src/test/run-pass/unsized2.rs
@@ -0,0 +1,82 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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 sized-ness checking in substitution.
+
+// Unbounded.
+fn f1<type X>(x: &X) {
+    f1::<X>(x);
+}
+fn f2<X>(x: &X) {
+    f1::<X>(x);
+    f2::<X>(x);
+}
+
+// Bounded.
+trait T for type {}
+fn f3<type X: T>(x: &X) {
+    f3::<X>(x);
+}
+fn f4<X: T>(x: &X) {
+    f3::<X>(x);
+    f4::<X>(x);
+}
+
+// Self type.
+trait T2 for type {
+    fn f() -> ~Self;
+}
+struct S;
+impl T2 for S {
+    fn f() -> ~S {
+        ~S
+    }
+}
+fn f5<type X: T2>(x: &X) {
+    let _: ~X = T2::f();
+}
+fn f6<X: T2>(x: &X) {
+    let _: ~X = T2::f();
+}
+
+trait T3 for type {
+    fn f() -> ~Self;
+}
+impl T3 for S {
+    fn f() -> ~S {
+        ~S
+    }
+}
+fn f7<type X: T3>(x: &X) {
+    // This is valid, but the unsized bound on X is irrelevant because any type
+    // which implements T3 must have statically known size.
+    let _: ~X = T3::f();
+}
+
+trait T4<X> {
+    fn m1(x: &T4<X>);
+    fn m2(x: &T5<X>);
+}
+trait T5<type X> {
+    fn m1(x: &T4<X>); // not an error (for now)
+    fn m2(x: &T5<X>);
+}
+
+trait T6<X: T> {
+    fn m1(x: &T4<X>);
+    fn m2(x: &T5<X>);
+}
+trait T7<type X: T> {
+    fn m1(x: &T4<X>); // not an error (for now)
+    fn m2(x: &T5<X>);
+}
+
+pub fn main() {
+}