diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index ba18c02f52d..1f4ddd1a5d6 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -10,9 +10,10 @@
 
 use metadata::csearch;
 use middle::def::DefFn;
-use middle::subst::Subst;
+use middle::subst::{Subst, Substs, EnumeratedItems};
 use middle::ty::{TransmuteRestriction, ctxt, ty_bare_fn};
 use middle::ty::{mod, Ty};
+use util::ppaux::Repr;
 
 use syntax::abi::RustIntrinsic;
 use syntax::ast::DefId;
@@ -23,52 +24,31 @@ use syntax::parse::token;
 use syntax::visit::Visitor;
 use syntax::visit;
 
-fn type_size_is_affected_by_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, typ: Ty<'tcx>)
-                                                  -> bool {
-    let mut result = false;
-    ty::maybe_walk_ty(typ, |typ| {
-        match typ.sty {
-            ty::ty_uniq(_) | ty::ty_ptr(_) | ty::ty_rptr(..) |
-            ty::ty_bare_fn(..) | ty::ty_closure(..) => {
-                false
-            }
-            ty::ty_param(_) => {
-                result = true;
-                // No need to continue; we now know the result.
-                false
-            }
-            ty::ty_enum(did, substs) => {
-                for enum_variant in (*ty::enum_variants(tcx, did)).iter() {
-                    for argument_type in enum_variant.args.iter() {
-                        let argument_type = argument_type.subst(tcx, substs);
-                        result = result ||
-                            type_size_is_affected_by_type_parameters(
-                                tcx,
-                                argument_type);
-                    }
-                }
-
-                // Don't traverse substitutions.
-                false
-            }
-            ty::ty_struct(did, substs) => {
-                for field in ty::struct_fields(tcx, did, substs).iter() {
-                    result = result ||
-                        type_size_is_affected_by_type_parameters(tcx,
-                                                                 field.mt.ty);
-                }
-
-                // Don't traverse substitutions.
-                false
-            }
-            _ => true,
-        }
-    });
-    result
+pub fn check_crate(tcx: &ctxt) {
+    let mut visitor = IntrinsicCheckingVisitor {
+        tcx: tcx,
+        param_envs: Vec::new(),
+        dummy_sized_ty: ty::mk_int(),
+        dummy_unsized_ty: ty::mk_vec(tcx, ty::mk_int(), None),
+    };
+    visit::walk_crate(&mut visitor, tcx.map.krate());
 }
 
 struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
     tcx: &'a ctxt<'tcx>,
+
+    // As we traverse the AST, we keep a stack of the parameter
+    // environments for each function we encounter. When we find a
+    // call to `transmute`, we can check it in the context of the top
+    // of the stack (which ought not to be empty).
+    param_envs: Vec<ty::ParameterEnvironment<'tcx>>,
+
+    // Dummy sized/unsized types that use to substitute for type
+    // parameters in order to estimate how big a type will be for any
+    // possible instantiation of the type parameters in scope.  See
+    // `check_transmute` for more details.
+    dummy_sized_ty: Ty<'tcx>,
+    dummy_unsized_ty: Ty<'tcx>,
 }
 
 impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
@@ -97,26 +77,175 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
     }
 
     fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
-        if type_size_is_affected_by_type_parameters(self.tcx, from) {
-            span_err!(self.tcx.sess, span, E0139,
-                      "cannot transmute from a type that contains type parameters");
-        }
-        if type_size_is_affected_by_type_parameters(self.tcx, to) {
-            span_err!(self.tcx.sess, span, E0140,
-                      "cannot transmute to a type that contains type parameters");
+        // Find the parameter environment for the most recent function that
+        // we entered.
+
+        let param_env = match self.param_envs.last() {
+            Some(p) => p,
+            None => {
+                self.tcx.sess.span_bug(
+                    span,
+                    "transmute encountered outside of any fn");
+            }
+        };
+
+        // Simple case: no type parameters involved.
+        if
+            !ty::type_has_params(from) && !ty::type_has_self(from) &&
+            !ty::type_has_params(to) && !ty::type_has_self(to)
+        {
+            let restriction = TransmuteRestriction {
+                span: span,
+                original_from: from,
+                original_to: to,
+                substituted_from: from,
+                substituted_to: to,
+                id: id,
+            };
+            self.push_transmute_restriction(restriction);
+            return;
         }
 
-        let restriction = TransmuteRestriction {
-            span: span,
-            from: from,
-            to: to,
-            id: id,
-        };
+        // The rules around type parameters are a bit subtle. We are
+        // checking these rules before monomorphization, so there may
+        // be unsubstituted type parameters present in the
+        // types. Obviously we cannot create LLVM types for those.
+        // However, if a type parameter appears only indirectly (i.e.,
+        // through a pointer), it does not necessarily affect the
+        // size, so that should be allowed. The only catch is that we
+        // DO want to be careful around unsized type parameters, since
+        // fat pointers have a different size than a thin pointer, and
+        // hence `&T` and `&U` have different sizes if `T : Sized` but
+        // `U : Sized` does not hold.
+        //
+        // However, it's not as simple as checking whether `T :
+        // Sized`, because even if `T : Sized` does not hold, that
+        // just means that `T` *may* not be sized.  After all, even a
+        // type parameter `Sized? T` could be bound to a sized
+        // type. (Issue #20116)
+        //
+        // To handle this, we first check for "interior" type
+        // parameters, which are always illegal. If there are none of
+        // those, then we know that the only way that all type
+        // parameters `T` are referenced indirectly, e.g. via a
+        // pointer type like `&T`. In that case, we only care whether
+        // `T` is sized or not, because that influences whether `&T`
+        // is a thin or fat pointer.
+        //
+        // One could imagine establishing a sophisticated constraint
+        // system to ensure that the transmute is legal, but instead
+        // we do something brutally dumb. We just substitute dummy
+        // sized or unsized types for every type parameter in scope,
+        // exhaustively checking all possible combinations. Here are some examples:
+        //
+        // ```
+        // fn foo<T,U>() {
+        //     // T=int, U=int
+        // }
+        //
+        // fn bar<Sized? T,U>() {
+        //     // T=int, U=int
+        //     // T=[int], U=int
+        // }
+        //
+        // fn baz<Sized? T, Sized?U>() {
+        //     // T=int, U=int
+        //     // T=[int], U=int
+        //     // T=int, U=[int]
+        //     // T=[int], U=[int]
+        // }
+        // ```
+        //
+        // In all cases, we keep the original unsubstituted types
+        // around for error reporting.
+
+        let from_tc = ty::type_contents(self.tcx, from);
+        let to_tc = ty::type_contents(self.tcx, to);
+        if from_tc.interior_param() || to_tc.interior_param() {
+            span_err!(self.tcx.sess, span, E0139,
+                      "cannot transmute to or from a type that contains \
+                       type parameters in its interior");
+            return;
+        }
+
+        let mut substs = param_env.free_substs.clone();
+        self.with_each_combination(
+            param_env,
+            param_env.free_substs.types.iter_enumerated(),
+            &mut substs,
+            &mut |substs| {
+                let restriction = TransmuteRestriction {
+                    span: span,
+                    original_from: from,
+                    original_to: to,
+                    substituted_from: from.subst(self.tcx, substs),
+                    substituted_to: to.subst(self.tcx, substs),
+                    id: id,
+                };
+                self.push_transmute_restriction(restriction);
+            });
+    }
+
+    fn with_each_combination(&self,
+                             param_env: &ty::ParameterEnvironment<'tcx>,
+                             mut types_in_scope: EnumeratedItems<Ty<'tcx>>,
+                             substs: &mut Substs<'tcx>,
+                             callback: &mut FnMut(&Substs<'tcx>))
+    {
+        // This parameter invokes `callback` many times with different
+        // substitutions that replace all the parameters in scope with
+        // either `int` or `[int]`, depending on whether the type
+        // parameter is known to be sized. See big comment above for
+        // an explanation of why this is a reasonable thing to do.
+
+        match types_in_scope.next() {
+            None => {
+                debug!("with_each_combination(substs={})",
+                       substs.repr(self.tcx));
+
+                callback.call_mut((substs,));
+            }
+
+            Some((space, index, &param_ty)) => {
+                debug!("with_each_combination: space={}, index={}, param_ty={}",
+                       space, index, param_ty.repr(self.tcx));
+
+                if !ty::type_is_sized(self.tcx, param_ty, param_env) {
+                    debug!("with_each_combination: param_ty is not known to be sized");
+
+                    substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
+                    self.with_each_combination(param_env, types_in_scope.clone(), substs, callback);
+                }
+
+                substs.types.get_mut_slice(space)[index] = self.dummy_sized_ty;
+                self.with_each_combination(param_env, types_in_scope, substs, callback);
+            }
+        }
+    }
+
+    fn push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
+        debug!("Pushing transmute restriction: {}", restriction.repr(self.tcx));
         self.tcx.transmute_restrictions.borrow_mut().push(restriction);
     }
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
+    fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
+                b: &'v ast::Block, s: Span, id: ast::NodeId) {
+        match fk {
+            visit::FkItemFn(..) | visit::FkMethod(..) => {
+                let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
+                self.param_envs.push(param_env);
+                visit::walk_fn(self, fk, fd, b, s);
+                self.param_envs.pop();
+            }
+            visit::FkFnBlock(..) => {
+                visit::walk_fn(self, fk, fd, b, s);
+            }
+        }
+
+    }
+
     fn visit_expr(&mut self, expr: &ast::Expr) {
         if let ast::ExprPath(..) = expr.node {
             match ty::resolve_expr(self.tcx, expr) {
@@ -144,7 +273,13 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
     }
 }
 
-pub fn check_crate(tcx: &ctxt) {
-    visit::walk_crate(&mut IntrinsicCheckingVisitor { tcx: tcx },
-                      tcx.map.krate());
+impl<'tcx> Repr<'tcx> for TransmuteRestriction<'tcx> {
+    fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+        format!("TransmuteRestriction(id={}, original=({},{}), substituted=({},{}))",
+                self.id,
+                self.original_from.repr(tcx),
+                self.original_to.repr(tcx),
+                self.substituted_from.repr(tcx),
+                self.substituted_to.repr(tcx))
+    }
 }
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index abacad7d37c..8d920e0a821 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -487,6 +487,7 @@ impl<T> VecPerParamSpace<T> {
     }
 }
 
+#[deriving(Clone)]
 pub struct EnumeratedItems<'a,T:'a> {
     vec: &'a VecPerParamSpace<T>,
     space_index: uint,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 731ad64799e..b3e9f85c69c 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -62,7 +62,7 @@ use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
 use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
 use util::ppaux::{trait_store_to_string, ty_to_string};
 use util::ppaux::{Repr, UserString};
-use util::common::{indenter, memoized, ErrorReported};
+use util::common::{memoized, ErrorReported};
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::{FnvHashMap};
 
@@ -590,16 +590,33 @@ pub enum vtable_origin<'tcx> {
 pub type ObjectCastMap<'tcx> = RefCell<NodeMap<Rc<ty::PolyTraitRef<'tcx>>>>;
 
 /// A restriction that certain types must be the same size. The use of
-/// `transmute` gives rise to these restrictions.
+/// `transmute` gives rise to these restrictions. These generally
+/// cannot be checked until trans; therefore, each call to `transmute`
+/// will push one or more such restriction into the
+/// `transmute_restrictions` vector during `intrinsicck`. They are
+/// then checked during `trans` by the fn `check_intrinsics`.
 #[deriving(Copy)]
 pub struct TransmuteRestriction<'tcx> {
-    /// The span from whence the restriction comes.
+    /// The span whence the restriction comes.
     pub span: Span,
+
     /// The type being transmuted from.
-    pub from: Ty<'tcx>,
+    pub original_from: Ty<'tcx>,
+
     /// The type being transmuted to.
-    pub to: Ty<'tcx>,
-    /// NodeIf of the transmute intrinsic.
+    pub original_to: Ty<'tcx>,
+
+    /// The type being transmuted from, with all type parameters
+    /// substituted for an arbitrary representative. Not to be shown
+    /// to the end user.
+    pub substituted_from: Ty<'tcx>,
+
+    /// The type being transmuted to, with all type parameters
+    /// substituted for an arbitrary representative. Not to be shown
+    /// to the end user.
+    pub substituted_to: Ty<'tcx>,
+
+    /// NodeId of the transmute intrinsic.
     pub id: ast::NodeId,
 }
 
@@ -2856,6 +2873,7 @@ def_type_content_sets! {
         // Things that are interior to the value (first nibble):
         InteriorUnsized                     = 0b0000_0000__0000_0000__0001,
         InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
+        InteriorParam                       = 0b0000_0000__0000_0000__0100,
         // InteriorAll                         = 0b00000000__00000000__1111,
 
         // Things that are owned by the value (second and third nibbles):
@@ -2910,6 +2928,10 @@ impl TypeContents {
         !self.intersects(TC::Nonsized)
     }
 
+    pub fn interior_param(&self) -> bool {
+        self.intersects(TC::InteriorParam)
+    }
+
     pub fn interior_unsafe(&self) -> bool {
         self.intersects(TC::InteriorUnsafe)
     }
@@ -3038,7 +3060,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
             }
 
             ty_closure(ref c) => {
-                closure_contents(cx, &**c) | TC::ReachesFfiUnsafe
+                closure_contents(&**c) | TC::ReachesFfiUnsafe
             }
 
             ty_uniq(typ) => {
@@ -3049,7 +3071,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
             }
 
             ty_trait(box TyTrait { bounds, .. }) => {
-                object_contents(cx, bounds) | TC::ReachesFfiUnsafe | TC::Nonsized
+                object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized
             }
 
             ty_ptr(ref mt) => {
@@ -3159,26 +3181,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
                 apply_lang_items(cx, did, res)
             }
 
-            ty_param(p) => {
-                // We only ever ask for the kind of types that are defined in
-                // the current crate; therefore, the only type parameters that
-                // could be in scope are those defined in the current crate.
-                // If this assertion fails, it is likely because of a
-                // failure of the cross-crate inlining code to translate a
-                // def-id.
-                assert_eq!(p.def_id.krate, ast::LOCAL_CRATE);
-
-                let ty_param_defs = cx.ty_param_defs.borrow();
-                let tp_def = &(*ty_param_defs)[p.def_id.node];
-                kind_bounds_to_contents(
-                    cx,
-                    tp_def.bounds.builtin_bounds,
-                    tp_def.bounds.trait_bounds[])
-            }
-
-            ty_infer(_) => {
-                // This occurs during coherence, but shouldn't occur at other
-                // times.
+            ty_param(_) => {
                 TC::All
             }
 
@@ -3188,6 +3191,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
                 result.unsafe_pointer() | TC::Nonsized
             }
 
+            ty_infer(_) |
             ty_err => {
                 cx.sess.bug("asked to compute contents of error type");
             }
@@ -3227,10 +3231,10 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
         b | (TC::ReachesBorrowed).when(region != ty::ReStatic)
     }
 
-    fn closure_contents(cx: &ctxt, cty: &ClosureTy) -> TypeContents {
+    fn closure_contents(cty: &ClosureTy) -> TypeContents {
         // Closure contents are just like trait contents, but with potentially
         // even more stuff.
-        let st = object_contents(cx, cty.bounds);
+        let st = object_contents(cty.bounds);
 
         let st = match cty.store {
             UniqTraitStore => {
@@ -3244,47 +3248,18 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
         st
     }
 
-    fn object_contents(cx: &ctxt,
-                       bounds: ExistentialBounds)
-                       -> TypeContents {
-        // These are the type contents of the (opaque) interior
-        kind_bounds_to_contents(cx, bounds.builtin_bounds, &[])
-    }
-
-    fn kind_bounds_to_contents<'tcx>(cx: &ctxt<'tcx>,
-                                     bounds: BuiltinBounds,
-                                     traits: &[Rc<PolyTraitRef<'tcx>>])
-                                     -> TypeContents {
-        let _i = indenter();
-        let mut tc = TC::All;
-        each_inherited_builtin_bound(cx, bounds, traits, |bound| {
+    fn object_contents(bounds: ExistentialBounds) -> TypeContents {
+        // These are the type contents of the (opaque) interior. We
+        // make no assumptions (other than that it cannot have an
+        // in-scope type parameter within, which makes no sense).
+        let mut tc = TC::All - TC::InteriorParam;
+        for bound in bounds.builtin_bounds.iter() {
             tc = tc - match bound {
                 BoundSync | BoundSend | BoundCopy => TC::None,
                 BoundSized => TC::Nonsized,
             };
-        });
-        return tc;
-
-        // Iterates over all builtin bounds on the type parameter def, including
-        // those inherited from traits with builtin-kind-supertraits.
-        fn each_inherited_builtin_bound<'tcx, F>(cx: &ctxt<'tcx>,
-                                                 bounds: BuiltinBounds,
-                                                 traits: &[Rc<PolyTraitRef<'tcx>>],
-                                                 mut f: F) where
-            F: FnMut(BuiltinBound),
-        {
-            for bound in bounds.iter() {
-                f(bound);
-            }
-
-            each_bound_trait_and_supertraits(cx, traits, |trait_ref| {
-                let trait_def = lookup_trait_def(cx, trait_ref.def_id());
-                for bound in trait_def.bounds.builtin_bounds.iter() {
-                    f(bound);
-                }
-                true
-            });
         }
+        return tc;
     }
 }
 
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 6b0baa5d05e..d49018e00c1 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -32,7 +32,7 @@ use middle::ty::{mod, Ty};
 use syntax::abi::RustIntrinsic;
 use syntax::ast;
 use syntax::parse::token;
-use util::ppaux::ty_to_string;
+use util::ppaux::{Repr, ty_to_string};
 
 pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option<ValueRef> {
     let name = match token::get_ident(item.ident).get() {
@@ -90,46 +90,53 @@ pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Opti
 /// Performs late verification that intrinsics are used correctly. At present,
 /// the only intrinsic that needs such verification is `transmute`.
 pub fn check_intrinsics(ccx: &CrateContext) {
-    for transmute_restriction in ccx.tcx()
-                                    .transmute_restrictions
-                                    .borrow()
-                                    .iter() {
+    let mut last_failing_id = None;
+    for transmute_restriction in ccx.tcx().transmute_restrictions.borrow().iter() {
+        // Sometimes, a single call to transmute will push multiple
+        // type pairs to test in order to exhaustively test the
+        // possibility around a type parameter. If one of those fails,
+        // there is no sense reporting errors on the others.
+        if last_failing_id == Some(transmute_restriction.id) {
+            continue;
+        }
+
+        debug!("transmute_restriction: {}", transmute_restriction.repr(ccx.tcx()));
+
+        assert!(!ty::type_has_params(transmute_restriction.substituted_from));
+        assert!(!ty::type_has_params(transmute_restriction.substituted_to));
+
         let llfromtype = type_of::sizing_type_of(ccx,
-                                                 transmute_restriction.from);
+                                                 transmute_restriction.substituted_from);
         let lltotype = type_of::sizing_type_of(ccx,
-                                               transmute_restriction.to);
+                                               transmute_restriction.substituted_to);
         let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
         let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
         if from_type_size != to_type_size {
-            ccx.sess()
-               .span_err(transmute_restriction.span,
-                format!("transmute called on types with different sizes: \
-                         {} ({} bit{}) to {} ({} bit{})",
-                        ty_to_string(ccx.tcx(), transmute_restriction.from),
-                        from_type_size as uint,
-                        if from_type_size == 1 {
-                            ""
-                        } else {
-                            "s"
-                        },
-                        ty_to_string(ccx.tcx(), transmute_restriction.to),
-                        to_type_size as uint,
-                        if to_type_size == 1 {
-                            ""
-                        } else {
-                            "s"
-                        })[]);
-        }
-        if type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) ||
-           type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) {
-            ccx.sess()
-               .add_lint(::lint::builtin::FAT_PTR_TRANSMUTES,
-                         transmute_restriction.id,
-                         transmute_restriction.span,
-                         format!("Transmuting fat pointer types; {} to {}.\
-                                  Beware of relying on the compiler's representation",
-                                 ty_to_string(ccx.tcx(), transmute_restriction.from),
-                                 ty_to_string(ccx.tcx(), transmute_restriction.to)));
+            last_failing_id = Some(transmute_restriction.id);
+
+            if transmute_restriction.original_from != transmute_restriction.substituted_from {
+                ccx.sess().span_err(
+                    transmute_restriction.span,
+                    format!("transmute called on types with potentially different sizes: \
+                             {} (could be {} bit{}) to {} (could be {} bit{})",
+                            ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+                            from_type_size as uint,
+                            if from_type_size == 1 {""} else {"s"},
+                            ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+                            to_type_size as uint,
+                            if to_type_size == 1 {""} else {"s"}).as_slice());
+            } else {
+                ccx.sess().span_err(
+                    transmute_restriction.span,
+                    format!("transmute called on types with different sizes: \
+                             {} ({} bit{}) to {} ({} bit{})",
+                            ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+                            from_type_size as uint,
+                            if from_type_size == 1 {""} else {"s"},
+                            ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+                            to_type_size as uint,
+                            if to_type_size == 1 {""} else {"s"}).as_slice());
+            }
         }
     }
     ccx.sess().abort_if_errors();
diff --git a/src/test/compile-fail/transmute-different-sizes.rs b/src/test/compile-fail/transmute-different-sizes.rs
index abdfe983e3a..5c61212a7f5 100644
--- a/src/test/compile-fail/transmute-different-sizes.rs
+++ b/src/test/compile-fail/transmute-different-sizes.rs
@@ -21,7 +21,7 @@ unsafe fn f() {
 
 unsafe fn g<T>(x: &T) {
     let _: i8 = transmute(x);
-    //~^ ERROR transmute called on types with different sizes
+    //~^ ERROR transmute called on types with potentially different sizes
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/transmute-fat-pointers.rs b/src/test/compile-fail/transmute-fat-pointers.rs
new file mode 100644
index 00000000000..5e81a4cec22
--- /dev/null
+++ b/src/test/compile-fail/transmute-fat-pointers.rs
@@ -0,0 +1,41 @@
+// Copyright 2012 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.
+
+// Tests that are conservative around thin/fat pointer mismatches.
+
+#![allow(dead_code)]
+
+use std::mem::transmute;
+
+fn a<T, Sized? U>(x: &[T]) -> &U {
+    unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+}
+
+fn b<Sized? T, Sized? U>(x: &T) -> &U {
+    unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+}
+
+fn c<T, U>(x: &T) -> &U {
+    unsafe { transmute(x) }
+}
+
+fn d<T, U>(x: &[T]) -> &[U] {
+    unsafe { transmute(x) }
+}
+
+fn e<Sized? T, U>(x: &T) -> &U {
+    unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+}
+
+fn f<T, Sized? U>(x: &T) -> &U {
+    unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/transmute-impl.rs b/src/test/compile-fail/transmute-impl.rs
new file mode 100644
index 00000000000..8b5a8c679b2
--- /dev/null
+++ b/src/test/compile-fail/transmute-impl.rs
@@ -0,0 +1,33 @@
+// 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.
+
+// Tests that are conservative around thin/fat pointer mismatches.
+
+#![allow(dead_code)]
+
+use std::mem::transmute;
+
+struct Foo<Sized? T> {
+    t: Box<T>
+}
+
+impl<Sized? T> Foo<T> {
+    fn m(x: &T) -> &int where T : Sized {
+        // OK here, because T : Sized is in scope.
+        unsafe { transmute(x) }
+    }
+
+    fn n(x: &T) -> &int {
+        // Not OK here, because T : Sized is not in scope.
+        unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+    }
+}
+
+fn main() { }