about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-12-22 12:51:23 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-12-22 12:51:23 -0800
commitde11710d807bed5c0a29cc0413d404552a42c89d (patch)
treea352475a1db5cdc5a19f557ba66a375766cda87c
parent459f3b2cfa0e618d6e28ce564a363a9477567f71 (diff)
parent763152b995bb506ac88c852a030c84a012bcf983 (diff)
downloadrust-de11710d807bed5c0a29cc0413d404552a42c89d.tar.gz
rust-de11710d807bed5c0a29cc0413d404552a42c89d.zip
rollup merge of #19891: nikomatsakis/unique-fn-types-3
Conflicts:
	src/libcore/str.rs
	src/librustc_trans/trans/closure.rs
	src/librustc_typeck/collect.rs
	src/libstd/path/posix.rs
	src/libstd/path/windows.rs
-rw-r--r--src/libcollections/btree/map.rs2
-rw-r--r--src/libcollections/btree/set.rs1
-rw-r--r--src/libcollections/vec_map.rs3
-rw-r--r--src/libcore/iter.rs3
-rw-r--r--src/libcore/str.rs1
-rw-r--r--src/librustc/metadata/decoder.rs2
-rw-r--r--src/librustc/metadata/tydecode.rs6
-rw-r--r--src/librustc/metadata/tyencode.rs7
-rw-r--r--src/librustc/middle/astencode.rs25
-rw-r--r--src/librustc/middle/check_const.rs6
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs10
-rw-r--r--src/librustc/middle/fast_reject.rs2
-rw-r--r--src/librustc/middle/infer/coercion.rs116
-rw-r--r--src/librustc/middle/infer/combine.rs11
-rw-r--r--src/librustc/middle/intrinsicck.rs4
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/middle/traits/select.rs6
-rw-r--r--src/librustc/middle/ty.rs84
-rw-r--r--src/librustc/middle/ty_fold.rs4
-rw-r--r--src/librustc/util/ppaux.rs16
-rw-r--r--src/librustc_driver/test.rs13
-rw-r--r--src/librustc_trans/trans/base.rs15
-rw-r--r--src/librustc_trans/trans/basic_block.rs3
-rw-r--r--src/librustc_trans/trans/callee.rs15
-rw-r--r--src/librustc_trans/trans/closure.rs7
-rw-r--r--src/librustc_trans/trans/consts.rs11
-rw-r--r--src/librustc_trans/trans/debuginfo.rs6
-rw-r--r--src/librustc_trans/trans/expr.rs14
-rw-r--r--src/librustc_trans/trans/foreign.rs10
-rw-r--r--src/librustc_trans/trans/glue.rs3
-rw-r--r--src/librustc_trans/trans/intrinsic.rs2
-rw-r--r--src/librustc_trans/trans/meth.rs5
-rw-r--r--src/librustc_trans/trans/type_of.rs6
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/method/confirm.rs4
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs26
-rw-r--r--src/librustc_typeck/check/wf.rs2
-rw-r--r--src/librustc_typeck/check/writeback.rs24
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs14
-rw-r--r--src/librustc_typeck/lib.rs7
-rw-r--r--src/librustc_typeck/variance.rs5
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/html/markdown.rs20
-rw-r--r--src/libstd/collections/hash/map.rs8
-rw-r--r--src/libstd/collections/hash/set.rs3
-rw-r--r--src/libstd/path/posix.rs4
-rw-r--r--src/libstd/path/windows.rs10
-rw-r--r--src/libstd/thread_local/mod.rs24
-rw-r--r--src/libsyntax/ext/base.rs28
-rw-r--r--src/libunicode/u_str.rs3
-rw-r--r--src/test/compile-fail/borrowck-autoref-3261.rs2
-rw-r--r--src/test/compile-fail/cast-to-bare-fn.rs2
-rw-r--r--src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs15
-rw-r--r--src/test/compile-fail/fn-item-type.rs25
-rw-r--r--src/test/compile-fail/issue-10764.rs2
-rw-r--r--src/test/compile-fail/issue-9575.rs2
-rw-r--r--src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs2
-rw-r--r--src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs4
-rw-r--r--src/test/compile-fail/regions-lifetime-bounds-on-fns.rs2
-rw-r--r--src/test/compile-fail/regions-nested-fns.rs4
-rw-r--r--src/test/compile-fail/static-reference-to-fn-1.rs2
-rw-r--r--src/test/compile-fail/static-reference-to-fn-2.rs12
-rw-r--r--src/test/pretty/issue-4264.pp33
-rw-r--r--src/test/run-pass/const-extern-function.rs2
-rw-r--r--src/test/run-pass/extern-compare-with-return-type.rs12
-rw-r--r--src/test/run-pass/fn-item-type-cast.rs28
-rw-r--r--src/test/run-pass/fn-item-type-coerce.rs23
-rw-r--r--src/test/run-pass/issue-10767.rs2
-rw-r--r--src/test/run-pass/issue-15444.rs1
73 files changed, 537 insertions, 255 deletions
diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index ebd9bd1f525..65c644da3d8 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -1230,6 +1230,7 @@ impl<K, V> BTreeMap<K, V> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((&'a K, &'a V)) -> &'a K = first; // coerce to fn pointer
 
         Keys { inner: self.iter().map(first) }
     }
@@ -1251,6 +1252,7 @@ impl<K, V> BTreeMap<K, V> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn values<'a>(&'a self) -> Values<'a, K, V> {
         fn second<A, B>((_, b): (A, B)) -> B { b }
+        let second: fn((&'a K, &'a V)) -> &'a V = second; // coerce to fn pointer
 
         Values { inner: self.iter().map(second) }
     }
diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs
index 3b403d45d82..2935692ed15 100644
--- a/src/libcollections/btree/set.rs
+++ b/src/libcollections/btree/set.rs
@@ -126,6 +126,7 @@ impl<T> BTreeSet<T> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn into_iter(self) -> IntoIter<T> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((T, ())) -> T = first; // coerce to fn pointer
 
         IntoIter { iter: self.map.into_iter().map(first) }
     }
diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs
index 999025840ca..207e27ccdcc 100644
--- a/src/libcollections/vec_map.rs
+++ b/src/libcollections/vec_map.rs
@@ -144,6 +144,7 @@ impl<V> VecMap<V> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn keys<'r>(&'r self) -> Keys<'r, V> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((uint, &'r V)) -> uint = first; // coerce to fn pointer
 
         Keys { iter: self.iter().map(first) }
     }
@@ -153,6 +154,7 @@ impl<V> VecMap<V> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn values<'r>(&'r self) -> Values<'r, V> {
         fn second<A, B>((_, b): (A, B)) -> B { b }
+        let second: fn((uint, &'r V)) -> &'r V = second; // coerce to fn pointer
 
         Values { iter: self.iter().map(second) }
     }
@@ -239,6 +241,7 @@ impl<V> VecMap<V> {
         fn filter<A>((i, v): (uint, Option<A>)) -> Option<(uint, A)> {
             v.map(|v| (i, v))
         }
+        let filter: fn((uint, Option<V>)) -> Option<(uint, V)> = filter; // coerce to fn ptr
 
         let values = replace(&mut self.v, vec!());
         IntoIter { iter: values.into_iter().enumerate().filter_map(filter) }
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index b592d1db274..1cd4d7b89d6 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -2612,6 +2612,9 @@ pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
         val.clone()
     }
 
+    // coerce to a fn pointer
+    let next: fn(&mut IterateState<T,F>) -> Option<T> = next;
+
     Unfold::new((f, Some(seed), true), next)
 }
 
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index f4a9e7e3f78..de5b34ff0ca 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -1310,6 +1310,7 @@ impl StrExt for str {
             else { line }
         }
 
+        let f: fn(&str) -> &str = f; // coerce to fn pointer
         LinesAny { inner: self.lines().map(f) }
     }
 
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index b869501237c..f05607a999b 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -700,7 +700,7 @@ pub fn get_enum_variants<'tcx>(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::Nod
                                 item, tcx, cdata);
         let name = item_name(&*intr, item);
         let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty {
-            ty::ty_bare_fn(ref f) =>
+            ty::ty_bare_fn(_, ref f) =>
                 (Some(ctor_ty), f.sig.0.inputs.clone(), None),
             _ => { // Nullary or struct enum variant.
                 let mut arg_names = Vec::new();
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 7683506f0f4..61ea93a9fdd 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -453,7 +453,11 @@ fn parse_ty<'a, 'tcx>(st: &mut PState<'a, 'tcx>, conv: conv_did) -> Ty<'tcx> {
         return ty::mk_closure(st.tcx, parse_closure_ty(st, |x,y| conv(x,y)));
       }
       'F' => {
-        return ty::mk_bare_fn(st.tcx, parse_bare_fn_ty(st, |x,y| conv(x,y)));
+          let def_id = parse_def(st, NominalType, |x,y| conv(x,y));
+          return ty::mk_bare_fn(st.tcx, Some(def_id), parse_bare_fn_ty(st, |x,y| conv(x,y)));
+      }
+      'G' => {
+          return ty::mk_bare_fn(st.tcx, None, parse_bare_fn_ty(st, |x,y| conv(x,y)));
       }
       '#' => {
         let pos = parse_hex(st);
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index ce63c467822..7fa23620af4 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -123,8 +123,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t
             mywrite!(w, "f");
             enc_closure_ty(w, cx, &**f);
         }
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(Some(def_id), ref f) => {
             mywrite!(w, "F");
+            mywrite!(w, "{}|", (cx.ds)(def_id));
+            enc_bare_fn_ty(w, cx, f);
+        }
+        ty::ty_bare_fn(None, ref f) => {
+            mywrite!(w, "G");
             enc_bare_fn_ty(w, cx, f);
         }
         ty::ty_infer(_) => {
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index ce86d6805b2..e8627dfa64b 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -1007,14 +1007,21 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
 
         self.emit_enum("AutoAdjustment", |this| {
             match *adj {
-                ty::AdjustAddEnv(store) => {
-                    this.emit_enum_variant("AutoAddEnv", 0, 1, |this| {
-                        this.emit_enum_variant_arg(0, |this| store.encode(this))
+                ty::AdjustAddEnv(def_id, store) => {
+                    this.emit_enum_variant("AdjustAddEnv", 0, 2, |this| {
+                        this.emit_enum_variant_arg(0, |this| def_id.encode(this));
+                        this.emit_enum_variant_arg(1, |this| store.encode(this))
+                    })
+                }
+
+                ty::AdjustReifyFnPointer(def_id) => {
+                    this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| {
+                        this.emit_enum_variant_arg(0, |this| def_id.encode(this))
                     })
                 }
 
                 ty::AdjustDerefRef(ref auto_deref_ref) => {
-                    this.emit_enum_variant("AutoDerefRef", 1, 1, |this| {
+                    this.emit_enum_variant("AdjustDerefRef", 2, 2, |this| {
                         this.emit_enum_variant_arg(0,
                             |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
                     })
@@ -1648,12 +1655,20 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
             this.read_enum_variant(&variants, |this, i| {
                 Ok(match i {
                     0 => {
+                        let def_id: ast::DefId =
+                            this.read_def_id(dcx);
                         let store: ty::TraitStore =
                             this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
 
-                        ty::AdjustAddEnv(store.tr(dcx))
+                        ty::AdjustAddEnv(def_id, store.tr(dcx))
                     }
                     1 => {
+                        let def_id: ast::DefId =
+                            this.read_def_id(dcx);
+
+                        ty::AdjustReifyFnPointer(def_id)
+                    }
+                    2 => {
                         let auto_deref_ref: ty::AutoDerefRef =
                             this.read_enum_variant_arg(0,
                                 |this| Ok(this.read_auto_deref_ref(dcx))).unwrap();
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index a91ea8bfef8..e08dd64d4d4 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -127,7 +127,11 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
         ast::ExprCast(ref from, _) => {
             let toty = ty::expr_ty(v.tcx, e);
             let fromty = ty::expr_ty(v.tcx, &**from);
-            if !ty::type_is_numeric(toty) && !ty::type_is_unsafe_ptr(toty) {
+            let is_legal_cast =
+                ty::type_is_numeric(toty) ||
+                ty::type_is_unsafe_ptr(toty) ||
+                (ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
+            if !is_legal_cast {
                 span_err!(v.tcx.sess, e.span, E0012,
                           "can not cast to `{}` in a constant expression",
                           ppaux::ty_to_string(v.tcx, toty));
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 0c0cba6e53e..52899aaba41 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -32,7 +32,7 @@ enum UnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::ty_bare_fn(ref f) => f.unsafety == ast::Unsafety::Unsafe,
+        ty::ty_bare_fn(_, ref f) => f.unsafety == ast::Unsafety::Unsafe,
         ty::ty_closure(ref f) => f.unsafety == ast::Unsafety::Unsafe,
         _ => false,
     }
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 4ee0064b0e6..7e31ae04ae0 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -824,10 +824,12 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
             None => { }
             Some(adjustment) => {
                 match *adjustment {
-                    ty::AdjustAddEnv(..) => {
-                        // Creating a closure consumes the input and stores it
-                        // into the resulting rvalue.
-                        debug!("walk_adjustment(AutoAddEnv)");
+                    ty::AdjustAddEnv(..) |
+                    ty::AdjustReifyFnPointer(..) => {
+                        // Creating a closure/fn-pointer consumes the
+                        // input and stores it into the resulting
+                        // rvalue.
+                        debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)");
                         let cmt_unadjusted =
                             return_if_err!(self.mc.cat_expr_unadjusted(expr));
                         self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs
index 297d6bcb03c..62cf47da687 100644
--- a/src/librustc/middle/fast_reject.rs
+++ b/src/librustc/middle/fast_reject.rs
@@ -83,7 +83,7 @@ pub fn simplify_type(tcx: &ty::ctxt,
         ty::ty_closure(ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(_, ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
         ty::ty_param(_) => {
diff --git a/src/librustc/middle/infer/coercion.rs b/src/librustc/middle/infer/coercion.rs
index 64bfd138802..ec83b8fae9b 100644
--- a/src/librustc/middle/infer/coercion.rs
+++ b/src/librustc/middle/infer/coercion.rs
@@ -84,10 +84,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let Coerce(ref v) = *self; v
     }
 
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.get_ref().infcx.tcx
+    }
+
     pub fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
         debug!("Coerce.tys({} => {})",
-               a.repr(self.get_ref().infcx.tcx),
-               b.repr(self.get_ref().infcx.tcx));
+               a.repr(self.tcx()),
+               b.repr(self.tcx()));
 
         // Consider coercing the subtype to a DST
         let unsize = self.unpack_actual_value(a, |a| {
@@ -170,13 +174,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
         self.unpack_actual_value(a, |a| {
             match a.sty {
-                ty::ty_bare_fn(ref a_f) => {
-                    // Bare functions are coercible to any closure type.
-                    //
-                    // FIXME(#3320) this should go away and be
-                    // replaced with proper inference, got a patch
-                    // underway - ndm
-                    self.coerce_from_bare_fn(a, a_f, b)
+                ty::ty_bare_fn(Some(a_def_id), ref a_f) => {
+                    // Function items are coercible to any closure
+                    // type; function pointers are not (that would
+                    // require double indirection).
+                    self.coerce_from_fn_item(a, a_def_id, a_f, b)
                 }
                 _ => {
                     // Otherwise, just use subtyping rules.
@@ -206,8 +208,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                                    mutbl_b: ast::Mutability)
                                    -> CoerceResult<'tcx> {
         debug!("coerce_borrowed_pointer(a={}, b={})",
-               a.repr(self.get_ref().infcx.tcx),
-               b.repr(self.get_ref().infcx.tcx));
+               a.repr(self.tcx()),
+               b.repr(self.tcx()));
 
         // If we have a parameter of type `&M T_a` and the value
         // provided is `expr`, we will be adding an implicit borrow,
@@ -227,7 +229,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             }
         };
 
-        let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
+        let a_borrowed = ty::mk_rptr(self.tcx(),
                                      r_borrow,
                                      mt {ty: inner_ty, mutbl: mutbl_b});
         try!(sub.tys(a_borrowed, b));
@@ -247,8 +249,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                       b: Ty<'tcx>)
                       -> CoerceResult<'tcx> {
         debug!("coerce_unsized(a={}, b={})",
-               a.repr(self.get_ref().infcx.tcx),
-               b.repr(self.get_ref().infcx.tcx));
+               a.repr(self.tcx()),
+               b.repr(self.tcx()));
 
         // Note, we want to avoid unnecessary unsizing. We don't want to coerce to
         // a DST unless we have to. This currently comes out in the wash since
@@ -268,7 +270,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                             let coercion = Coercion(self.get_ref().trace.clone());
                             let r_borrow = self.get_ref().infcx.next_region_var(coercion);
-                            let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
+                            let ty = ty::mk_rptr(self.tcx(),
                                                  r_borrow,
                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
@@ -292,7 +294,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                                 return Err(ty::terr_mutability);
                             }
 
-                            let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
+                            let ty = ty::mk_ptr(self.tcx(),
                                                  ty::mt{ty: ty, mutbl: mt_b.mutbl});
                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
                             debug!("Success, coerced with AutoDerefRef(1, \
@@ -311,7 +313,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 self.unpack_actual_value(t_a, |a| {
                     match self.unsize_ty(t_a, a, t_b) {
                         Some((ty, kind)) => {
-                            let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
+                            let ty = ty::mk_uniq(self.tcx(), ty);
                             try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
                             debug!("Success, coerced with AutoDerefRef(1, \
                                     AutoUnsizeUniq({}))", kind);
@@ -336,9 +338,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                  a: Ty<'tcx>,
                  ty_b: Ty<'tcx>)
                  -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
-        debug!("unsize_ty(a={}, ty_b={})", a, ty_b.repr(self.get_ref().infcx.tcx));
+        debug!("unsize_ty(a={}, ty_b={})", a, ty_b.repr(self.tcx()));
 
-        let tcx = self.get_ref().infcx.tcx;
+        let tcx = self.tcx();
 
         self.unpack_actual_value(ty_b, |b|
             match (&a.sty, &b.sty) {
@@ -412,7 +414,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                               b: Ty<'tcx>,
                               b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
     {
-        let tcx = self.get_ref().infcx.tcx;
+        let tcx = self.tcx();
 
         debug!("coerce_borrowed_object(a={}, b={}, b_mutbl={})",
                a.repr(tcx),
@@ -431,7 +433,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                             b: Ty<'tcx>,
                             b_mutbl: ast::Mutability) -> CoerceResult<'tcx>
     {
-        let tcx = self.get_ref().infcx.tcx;
+        let tcx = self.tcx();
 
         debug!("coerce_unsafe_object(a={}, b={}, b_mutbl={})",
                a.repr(tcx),
@@ -451,7 +453,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
         G: FnOnce() -> ty::AutoRef<'tcx>,
     {
-        let tcx = self.get_ref().infcx.tcx;
+        let tcx = self.tcx();
 
         match a.sty {
             ty::ty_rptr(_, ty::mt{ty, mutbl}) => match ty.sty {
@@ -480,12 +482,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                               b: Ty<'tcx>)
                               -> CoerceResult<'tcx> {
         debug!("coerce_borrowed_fn(a={}, b={})",
-               a.repr(self.get_ref().infcx.tcx),
-               b.repr(self.get_ref().infcx.tcx));
+               a.repr(self.tcx()),
+               b.repr(self.tcx()));
 
         match a.sty {
-            ty::ty_bare_fn(ref f) => {
-                self.coerce_from_bare_fn(a, f, b)
+            ty::ty_bare_fn(Some(a_def_id), ref f) => {
+                self.coerce_from_fn_item(a, a_def_id, f, b)
             }
             _ => {
                 self.subtype(a, b)
@@ -493,32 +495,46 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         }
     }
 
-    ///  Attempts to coerce from a bare Rust function (`extern "Rust" fn`) into a closure or a
-    ///  `proc`.
-    fn coerce_from_bare_fn(&self, a: Ty<'tcx>, fn_ty_a: &ty::BareFnTy<'tcx>, b: Ty<'tcx>)
+    fn coerce_from_fn_item(&self,
+                           a: Ty<'tcx>,
+                           fn_def_id_a: ast::DefId,
+                           fn_ty_a: &ty::BareFnTy<'tcx>,
+                           b: Ty<'tcx>)
                            -> CoerceResult<'tcx> {
+        /*!
+         * Attempts to coerce from the type of a Rust function item
+         * into a closure or a `proc`.
+         */
+
         self.unpack_actual_value(b, |b| {
+            debug!("coerce_from_fn_item(a={}, b={})",
+                   a.repr(self.tcx()), b.repr(self.tcx()));
 
-            debug!("coerce_from_bare_fn(a={}, b={})",
-                   a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
+            match b.sty {
+                ty::ty_closure(ref f) => {
+                    if fn_ty_a.abi != abi::Rust || fn_ty_a.unsafety != ast::Unsafety::Normal {
+                        return self.subtype(a, b);
+                    }
 
-            if fn_ty_a.abi != abi::Rust || fn_ty_a.unsafety != ast::Unsafety::Normal {
-                return self.subtype(a, b);
+                    let fn_ty_b = (*f).clone();
+                    let adj = ty::AdjustAddEnv(fn_def_id_a, fn_ty_b.store);
+                    let a_closure = ty::mk_closure(self.tcx(),
+                                                   ty::ClosureTy {
+                                                       sig: fn_ty_a.sig.clone(),
+                                                       .. *fn_ty_b
+                                                   });
+                    try!(self.subtype(a_closure, b));
+                    Ok(Some(adj))
+                }
+                ty::ty_bare_fn(None, _) => {
+                    let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, (*fn_ty_a).clone());
+                    try!(self.subtype(a_fn_pointer, b));
+                    Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a)))
+                }
+                _ => {
+                    return self.subtype(a, b)
+                }
             }
-
-            let fn_ty_b = match b.sty {
-                ty::ty_closure(ref f) => (*f).clone(),
-                _ => return self.subtype(a, b)
-            };
-
-            let adj = ty::AdjustAddEnv(fn_ty_b.store);
-            let a_closure = ty::mk_closure(self.get_ref().infcx.tcx,
-                                           ty::ClosureTy {
-                                                sig: fn_ty_a.sig.clone(),
-                                                .. *fn_ty_b
-                                           });
-            try!(self.subtype(a_closure, b));
-            Ok(Some(adj))
         })
     }
 
@@ -528,8 +544,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                              mutbl_b: ast::Mutability)
                              -> CoerceResult<'tcx> {
         debug!("coerce_unsafe_ptr(a={}, b={})",
-               a.repr(self.get_ref().infcx.tcx),
-               b.repr(self.get_ref().infcx.tcx));
+               a.repr(self.tcx()),
+               b.repr(self.tcx()));
 
         let mt_a = match a.sty {
             ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
@@ -539,7 +555,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         };
 
         // Check that the types which they point at are compatible.
-        let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
+        let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty });
         try!(self.subtype(a_unsafe, b));
         if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) {
             return Err(ty::terr_mutability);
diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs
index 11ab44ba09f..14687b8fd75 100644
--- a/src/librustc/middle/infer/combine.rs
+++ b/src/librustc/middle/infer/combine.rs
@@ -568,11 +568,12 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C,
         }
       }
 
-      (&ty::ty_bare_fn(ref a_fty), &ty::ty_bare_fn(ref b_fty)) => {
-        this.bare_fn_tys(a_fty, b_fty).and_then(|fty| {
-            Ok(ty::mk_bare_fn(tcx, fty))
-        })
-      }
+        (&ty::ty_bare_fn(a_opt_def_id, ref a_fty), &ty::ty_bare_fn(b_opt_def_id, ref b_fty))
+            if a_opt_def_id == b_opt_def_id =>
+        {
+            let fty = try!(this.bare_fn_tys(a_fty, b_fty));
+            Ok(ty::mk_bare_fn(tcx, a_opt_def_id, fty))
+        }
 
       (&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => {
         this.closure_tys(&**a_fty, &**b_fty).and_then(|fty| {
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index ea19111ce3d..6acbc98b4b2 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -74,7 +74,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
 impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match ty::lookup_item_type(self.tcx, def_id).ty.sty {
-            ty::ty_bare_fn(ref bfty) => bfty.abi == RustIntrinsic,
+            ty::ty_bare_fn(_, ref bfty) => bfty.abi == RustIntrinsic,
             _ => return false
         };
         if def_id.krate == ast::LOCAL_CRATE {
@@ -123,7 +123,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
                 DefFn(did, _) if self.def_id_is_transmute(did) => {
                     let typ = ty::node_id_to_type(self.tcx, expr.id);
                     match typ.sty {
-                        ty_bare_fn(ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+                        ty_bare_fn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                             if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
                                 let from = bare_fn_ty.sig.0.inputs[0];
                                 self.check_transmute(expr.span, from, to, expr.id);
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 1c2ceea7716..006515ea0a0 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -441,8 +441,8 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
 
             Some(adjustment) => {
                 match *adjustment {
-                    ty::AdjustAddEnv(..) => {
-                        debug!("cat_expr(AdjustAddEnv): {}",
+                    ty::AdjustAddEnv(..) | ty::AdjustReifyFnPointer(..) => {
+                        debug!("cat_expr(AdjustAddEnv|AdjustReifyFnPointer): {}",
                                expr.repr(self.tcx()));
                         // Convert a bare fn to a closure by adding NULL env.
                         // Result is an rvalue.
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 2b42849a87b..f849f4c9b93 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -795,7 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::ty_bare_fn(ty::BareFnTy {
+            ty::ty_bare_fn(_, ty::BareFnTy {
                 unsafety: ast::Unsafety::Normal,
                 abi: abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -984,7 +984,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::ty_int(_) |
             ty::ty_bool |
             ty::ty_float(_) |
-            ty::ty_bare_fn(_) |
+            ty::ty_bare_fn(..) |
             ty::ty_char => {
                 // safe for everything
                 Ok(If(Vec::new()))
@@ -1543,7 +1543,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
         let sig = match self_ty.sty {
-            ty::ty_bare_fn(ty::BareFnTy {
+            ty::ty_bare_fn(_, ty::BareFnTy {
                 unsafety: ast::Unsafety::Normal,
                 abi: abi::Rust,
                 ref sig
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 8632862f26a..22fdea8afb5 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -293,7 +293,8 @@ pub enum Variance {
 
 #[deriving(Clone, Show)]
 pub enum AutoAdjustment<'tcx> {
-    AdjustAddEnv(ty::TraitStore),
+    AdjustAddEnv(ast::DefId, ty::TraitStore),
+    AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type
     AdjustDerefRef(AutoDerefRef<'tcx>)
 }
 
@@ -1245,11 +1246,17 @@ pub enum sty<'tcx> {
     ty_vec(Ty<'tcx>, Option<uint>), // Second field is length.
     ty_ptr(mt<'tcx>),
     ty_rptr(Region, mt<'tcx>),
-    ty_bare_fn(BareFnTy<'tcx>),
+
+    // If the def-id is Some(_), then this is the type of a specific
+    // fn item. Otherwise, if None(_), it a fn pointer type.
+    ty_bare_fn(Option<DefId>, BareFnTy<'tcx>),
+
     ty_closure(Box<ClosureTy<'tcx>>),
     ty_trait(Box<TyTrait<'tcx>>),
     ty_struct(DefId, Substs<'tcx>),
+
     ty_unboxed_closure(DefId, Region, Substs<'tcx>),
+
     ty_tup(Vec<Ty<'tcx>>),
 
     ty_param(ParamTy), // type parameter
@@ -2181,7 +2188,7 @@ impl FlagComputation {
                 self.add_tys(ts[]);
             }
 
-            &ty_bare_fn(ref f) => {
+            &ty_bare_fn(_, ref f) => {
                 self.add_fn_sig(&f.sig);
             }
 
@@ -2342,15 +2349,19 @@ pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, fty: ClosureTy<'tcx>) -> Ty<'tcx> {
     mk_t(cx, ty_closure(box fty))
 }
 
-pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>, fty: BareFnTy<'tcx>) -> Ty<'tcx> {
-    mk_t(cx, ty_bare_fn(fty))
+pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>,
+                        opt_def_id: Option<ast::DefId>,
+                        fty: BareFnTy<'tcx>) -> Ty<'tcx> {
+    mk_t(cx, ty_bare_fn(opt_def_id, fty))
 }
 
 pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>,
+                        def_id: ast::DefId,
                         input_tys: &[Ty<'tcx>],
                         output: Ty<'tcx>) -> Ty<'tcx> {
     let input_args = input_tys.iter().map(|ty| *ty).collect();
     mk_bare_fn(cx,
+               Some(def_id),
                BareFnTy {
                    unsafety: ast::Unsafety::Normal,
                    abi: abi::Rust,
@@ -2449,7 +2460,7 @@ pub fn maybe_walk_ty<'tcx>(ty: Ty<'tcx>, f: |Ty<'tcx>| -> bool) {
             }
         }
         ty_tup(ref ts) => { for tt in ts.iter() { maybe_walk_ty(*tt, |x| f(x)); } }
-        ty_bare_fn(ref ft) => {
+        ty_bare_fn(_, ref ft) => {
             for a in ft.sig.0.inputs.iter() { maybe_walk_ty(*a, |x| f(x)); }
             if let ty::FnConverging(output) = ft.sig.0.output {
                 maybe_walk_ty(output, f);
@@ -2932,7 +2943,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
             // Scalar and unique types are sendable, and durable
             ty_infer(ty::FreshIntTy(_)) |
             ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
-            ty_bare_fn(_) | ty::ty_char => {
+            ty_bare_fn(..) | ty::ty_char => {
                 TC::None
             }
 
@@ -3267,7 +3278,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool {
             ty_uint(_) |
             ty_float(_) |
             ty_str |
-            ty_bare_fn(_) |
+            ty_bare_fn(..) |
             ty_closure(_) |
             ty_infer(_) |
             ty_err |
@@ -3563,6 +3574,13 @@ pub fn type_is_bare_fn(ty: Ty) -> bool {
     }
 }
 
+pub fn type_is_bare_fn_item(ty: Ty) -> bool {
+    match ty.sty {
+        ty_bare_fn(Some(_), _) => true,
+        _ => false
+    }
+}
+
 pub fn type_is_fp(ty: Ty) -> bool {
     match ty.sty {
       ty_infer(FloatVar(_)) | ty_float(_) => true,
@@ -3795,7 +3813,7 @@ pub fn node_id_item_substs<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> ItemSubsts
 
 pub fn fn_is_variadic(fty: Ty) -> bool {
     match fty.sty {
-        ty_bare_fn(ref f) => f.sig.0.variadic,
+        ty_bare_fn(_, ref f) => f.sig.0.variadic,
         ty_closure(ref f) => f.sig.0.variadic,
         ref s => {
             panic!("fn_is_variadic() called on non-fn type: {}", s)
@@ -3805,7 +3823,7 @@ pub fn fn_is_variadic(fty: Ty) -> bool {
 
 pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> {
     match fty.sty {
-        ty_bare_fn(ref f) => &f.sig,
+        ty_bare_fn(_, ref f) => &f.sig,
         ty_closure(ref f) => &f.sig,
         ref s => {
             panic!("ty_fn_sig() called on non-fn type: {}", s)
@@ -3816,7 +3834,7 @@ pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> {
 /// Returns the ABI of the given function.
 pub fn ty_fn_abi(fty: Ty) -> abi::Abi {
     match fty.sty {
-        ty_bare_fn(ref f) => f.abi,
+        ty_bare_fn(_, ref f) => f.abi,
         ty_closure(ref f) => f.abi,
         _ => panic!("ty_fn_abi() called on non-fn type"),
     }
@@ -3843,7 +3861,7 @@ pub fn ty_closure_store(fty: Ty) -> TraitStore {
 
 pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> {
     match fty.sty {
-        ty_bare_fn(ref f) => f.sig.0.output,
+        ty_bare_fn(_, ref f) => f.sig.0.output,
         ty_closure(ref f) => f.sig.0.output,
         ref s => {
             panic!("ty_fn_ret() called on non-fn type: {}", s)
@@ -3853,7 +3871,7 @@ pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> FnOutput<'tcx> {
 
 pub fn is_fn_ty(fty: Ty) -> bool {
     match fty.sty {
-        ty_bare_fn(_) => true,
+        ty_bare_fn(..) => true,
         ty_closure(_) => true,
         _ => false
     }
@@ -3978,9 +3996,9 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
     return match adjustment {
         Some(adjustment) => {
             match *adjustment {
-                AdjustAddEnv(store) => {
+                AdjustAddEnv(_, store) => {
                     match unadjusted_ty.sty {
-                        ty::ty_bare_fn(ref b) => {
+                        ty::ty_bare_fn(Some(_), ref b) => {
                             let bounds = ty::ExistentialBounds {
                                 region_bound: ReStatic,
                                 builtin_bounds: all_builtin_bounds(),
@@ -3997,7 +4015,21 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>,
                         }
                         ref b => {
                             cx.sess.bug(
-                                format!("add_env adjustment on non-bare-fn: \
+                                format!("add_env adjustment on non-fn-item: \
+                                         {}",
+                                        b).as_slice());
+                        }
+                    }
+                }
+
+                AdjustReifyFnPointer(_) => {
+                    match unadjusted_ty.sty {
+                        ty::ty_bare_fn(Some(_), ref b) => {
+                            ty::mk_bare_fn(cx, None, (*b).clone())
+                        }
+                        ref b => {
+                            cx.sess.bug(
+                                format!("AdjustReifyFnPointer adjustment on non-fn-item: \
                                          {}",
                                         b)[]);
                         }
@@ -4356,7 +4388,8 @@ pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
         ty_vec(_, None) => "slice".to_string(),
         ty_ptr(_) => "*-ptr".to_string(),
         ty_rptr(_, _) => "&-ptr".to_string(),
-        ty_bare_fn(_) => "extern fn".to_string(),
+        ty_bare_fn(Some(_), _) => format!("fn item"),
+        ty_bare_fn(None, _) => "fn pointer".to_string(),
         ty_closure(_) => "fn".to_string(),
         ty_trait(ref inner) => {
             format!("trait {}", item_path_str(cx, inner.principal.def_id()))
@@ -4547,6 +4580,10 @@ pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) {
                                     "concrete lifetime that was found is ",
                                     conc_region, "");
         }
+        terr_regions_overly_polymorphic(_, ty::ReInfer(ty::ReVar(_))) => {
+            // don't bother to print out the message below for
+            // inference variables, it's not very illuminating.
+        }
         terr_regions_overly_polymorphic(_, conc_region) => {
             note_and_explain_region(cx,
                                     "expected concrete lifetime is ",
@@ -5887,8 +5924,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -
                     region(state, r);
                     mt(state, m);
                 }
-                ty_bare_fn(ref b) => {
+                ty_bare_fn(opt_def_id, ref b) => {
                     byte!(14);
+                    hash!(opt_def_id);
                     hash!(b.unsafety);
                     hash!(b.abi);
                     fn_sig(state, &b.sig);
@@ -6203,7 +6241,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
             ty_str |
             ty_vec(_, _) |
             ty_ptr(_) |
-            ty_bare_fn(_) |
+            ty_bare_fn(..) |
             ty_tup(_) |
             ty_param(_) |
             ty_infer(_) |
@@ -6255,6 +6293,7 @@ impl<'tcx> AutoAdjustment<'tcx> {
     pub fn is_identity(&self) -> bool {
         match *self {
             AdjustAddEnv(..) => false,
+            AdjustReifyFnPointer(..) => false,
             AdjustDerefRef(ref r) => r.is_identity(),
         }
     }
@@ -6370,8 +6409,11 @@ impl DebruijnIndex {
 impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
         match *self {
-            AdjustAddEnv(ref trait_store) => {
-                format!("AdjustAddEnv({})", trait_store)
+            AdjustAddEnv(def_id, ref trait_store) => {
+                format!("AdjustAddEnv({},{})", def_id.repr(tcx), trait_store)
+            }
+            AdjustReifyFnPointer(def_id) => {
+                format!("AdjustAddEnv({})", def_id.repr(tcx))
             }
             AdjustDerefRef(ref data) => {
                 data.repr(tcx)
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index d69ae96d07e..a35ea30b217 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -538,8 +538,8 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
         ty::ty_tup(ref ts) => {
             ty::ty_tup(ts.fold_with(this))
         }
-        ty::ty_bare_fn(ref f) => {
-            ty::ty_bare_fn(f.fold_with(this))
+        ty::ty_bare_fn(opt_def_id, ref f) => {
+            ty::ty_bare_fn(opt_def_id, f.fold_with(this))
         }
         ty::ty_closure(ref f) => {
             ty::ty_closure(box f.fold_with(this))
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 5f61c04d366..a02004e6d18 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -254,12 +254,14 @@ pub fn vec_map_to_string<T, F>(ts: &[T], f: F) -> String where
 
 pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
     fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>,
+                               opt_def_id: Option<ast::DefId>,
                                unsafety: ast::Unsafety,
                                abi: abi::Abi,
                                ident: Option<ast::Ident>,
                                sig: &ty::PolyFnSig<'tcx>)
                                -> String {
         let mut s = String::new();
+
         match unsafety {
             ast::Unsafety::Normal => {}
             ast::Unsafety::Unsafe => {
@@ -284,6 +286,16 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
 
         push_sig_to_string(cx, &mut s, '(', ')', sig, "");
 
+        match opt_def_id {
+            Some(def_id) => {
+                s.push_str(" {");
+                let path_str = ty::item_path_str(cx, def_id);
+                s.push_str(path_str[]);
+                s.push_str("}");
+            }
+            None => { }
+        }
+
         s
     }
 
@@ -408,8 +420,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
         ty_closure(ref f) => {
             closure_to_string(cx, &**f)
         }
-        ty_bare_fn(ref f) => {
-            bare_fn_to_string(cx, f.unsafety, f.abi, None, &f.sig)
+        ty_bare_fn(opt_def_id, ref f) => {
+            bare_fn_to_string(cx, opt_def_id, f.unsafety, f.abi, None, &f.sig)
         }
         ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty),
         ty_err => "[type error]".to_string(),
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 090d6a7a3ca..526bbca8d70 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -253,7 +253,18 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
                 output_ty: Ty<'tcx>)
                 -> Ty<'tcx>
     {
-        ty::mk_ctor_fn(self.infcx.tcx, input_tys, output_ty)
+        let input_args = input_tys.iter().map(|ty| *ty).collect();
+        ty::mk_bare_fn(self.infcx.tcx,
+                       None,
+                       ty::BareFnTy {
+                           unsafety: ast::Unsafety::Normal,
+                           abi: abi::Rust,
+                           sig: ty::Binder(ty::FnSig {
+                               inputs: input_args,
+                               output: ty::FnConverging(output_ty),
+                               variadic: false
+                           })
+                       })
     }
 
     pub fn t_nil(&self) -> Ty<'tcx> {
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index a18d403bd95..f49fc7f06c5 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -282,7 +282,7 @@ pub fn kind_for_unboxed_closure(ccx: &CrateContext, closure_id: ast::DefId)
 pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
     let (inputs, output, abi, env) = match fn_ty.sty {
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(_, ref f) => {
             (f.sig.0.inputs.clone(), f.sig.0.output, f.abi, None)
         }
         ty::ty_closure(ref f) => {
@@ -542,6 +542,7 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs);
         let llty = type_of_dtor(ccx, class_ty);
         let dtor_ty = ty::mk_ctor_fn(ccx.tcx(),
+                                     did,
                                      &[glue::get_drop_glue_type(ccx, t)],
                                      ty::mk_nil(ccx.tcx()));
         get_extern_fn(ccx,
@@ -955,7 +956,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      did: ast::DefId, t: Ty<'tcx>) -> ValueRef {
     let name = csearch::get_symbol(&ccx.sess().cstore, did);
     match t.sty {
-        ty::ty_bare_fn(ref fn_ty) => {
+        ty::ty_bare_fn(_, ref fn_ty) => {
             match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
                 Rust | RustCall => {
                     get_extern_rust_fn(ccx, t, name[], did)
@@ -2014,7 +2015,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let tcx = ccx.tcx();
 
     let result_ty = match ctor_ty.sty {
-        ty::ty_bare_fn(ref bft) => bft.sig.0.output.unwrap(),
+        ty::ty_bare_fn(_, ref bft) => bft.sig.0.output.unwrap(),
         _ => ccx.sess().bug(
             format!("trans_enum_variant_constructor: \
                      unexpected ctor return type {}",
@@ -2086,7 +2087,7 @@ fn trans_enum_variant_or_tuple_like_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx
     let ctor_ty = ctor_ty.subst(ccx.tcx(), param_substs);
 
     let result_ty = match ctor_ty.sty {
-        ty::ty_bare_fn(ref bft) => bft.sig.0.output,
+        ty::ty_bare_fn(_, ref bft) => bft.sig.0.output,
         _ => ccx.sess().bug(
             format!("trans_enum_variant_or_tuple_like_struct: \
                      unexpected ctor return type {}",
@@ -2421,7 +2422,7 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                          node_type: Ty<'tcx>)
                          -> ValueRef {
     match node_type.sty {
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(_, ref f) => {
             assert!(f.abi == Rust || f.abi == RustCall);
         }
         _ => panic!("expected bare rust fn")
@@ -2438,7 +2439,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
 
     let (fn_sig, abi, has_env) = match fn_ty.sty {
         ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
-        ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
+        ty::ty_bare_fn(_, ref f) => (f.sig.clone(), f.abi, false),
         ty::ty_unboxed_closure(closure_did, _, ref substs) => {
             let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
             let ref function_type = (*unboxed_closures)[closure_did]
@@ -2467,7 +2468,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<
                 _ => ccx.sess().bug("expected tuple'd inputs")
             }
         },
-        ty::ty_bare_fn(_) if abi == RustCall => {
+        ty::ty_bare_fn(..) if abi == RustCall => {
             let mut inputs = vec![fn_sig.0.inputs[0]];
 
             match fn_sig.0.inputs[1].sty {
diff --git a/src/librustc_trans/trans/basic_block.rs b/src/librustc_trans/trans/basic_block.rs
index 476f5e2d618..ab25343ff5f 100644
--- a/src/librustc_trans/trans/basic_block.rs
+++ b/src/librustc_trans/trans/basic_block.rs
@@ -37,7 +37,10 @@ impl BasicBlock {
 
     pub fn pred_iter(self) -> Preds {
         fn is_a_terminator_inst(user: &Value) -> bool { user.is_a_terminator_inst() }
+        let is_a_terminator_inst: fn(&Value) -> bool = is_a_terminator_inst;
+
         fn get_parent(user: Value) -> BasicBlock { user.get_parent().unwrap() }
+        let get_parent: fn(Value) -> BasicBlock = get_parent;
 
         self.as_value().user_iter()
             .filter(is_a_terminator_inst)
diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs
index ec3a81afaa0..7f22faf050d 100644
--- a/src/librustc_trans/trans/callee.rs
+++ b/src/librustc_trans/trans/callee.rs
@@ -21,7 +21,8 @@ pub use self::CallArgs::*;
 use arena::TypedArena;
 use back::{abi,link};
 use session;
-use llvm::{ValueRef, get_param};
+use llvm::{ValueRef};
+use llvm::get_param;
 use llvm;
 use metadata::csearch;
 use middle::def;
@@ -158,7 +159,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
                 }
             }
             def::DefFn(did, _) if match expr_ty.sty {
-                ty::ty_bare_fn(ref f) => f.abi == synabi::RustIntrinsic,
+                ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
                 _ => false
             } => {
                 let substs = node_id_substs(bcx, ExprId(ref_expr.id));
@@ -275,15 +276,16 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
 
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
-    let (input_tys, output_ty) =
+    let (opt_def_id, input_tys, output_ty) =
         match bare_fn_ty.sty {
-            ty::ty_bare_fn(ty::BareFnTy { unsafety: ast::Unsafety::Normal,
+            ty::ty_bare_fn(opt_def_id,
+                           ty::BareFnTy { unsafety: ast::Unsafety::Normal,
                                           abi: synabi::Rust,
                                           sig: ty::Binder(ty::FnSig { inputs: ref input_tys,
                                                                       output: output_ty,
                                                                       variadic: false })}) =>
             {
-                (input_tys, output_ty)
+                (opt_def_id, input_tys, output_ty)
             }
 
             _ => {
@@ -293,6 +295,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
         };
     let tuple_input_ty = ty::mk_tup(tcx, input_tys.to_vec());
     let tuple_fn_ty = ty::mk_bare_fn(tcx,
+                                     opt_def_id,
                                      ty::BareFnTy { unsafety: ast::Unsafety::Normal,
                                                     abi: synabi::RustCall,
                                                     sig: ty::Binder(ty::FnSig {
@@ -655,7 +658,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
     let mut bcx = callee.bcx;
 
     let (abi, ret_ty) = match callee_ty.sty {
-        ty::ty_bare_fn(ref f) => (f.abi, f.sig.0.output),
+        ty::ty_bare_fn(_, ref f) => (f.abi, f.sig.0.output),
         ty::ty_closure(ref f) => (f.abi, f.sig.0.output),
         _ => panic!("expected bare rust fn or closure in trans_call_inner")
     };
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 8e56ef3c6f3..28716f0a481 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -13,7 +13,6 @@ pub use self::ClosureKind::*;
 use back::abi;
 use back::link::mangle_internal_name_by_path_and_seq;
 use llvm::ValueRef;
-use middle::def;
 use middle::mem_categorization::Typer;
 use trans::adt;
 use trans::base::*;
@@ -603,7 +602,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
 
 pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                          closure_ty: Ty<'tcx>,
-                                         def: def::Def,
+                                         def_id: ast::DefId,
                                          fn_ptr: ValueRef,
                                          is_local: bool) -> ValueRef {
 
@@ -697,11 +696,11 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 pub fn make_closure_from_bare_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                              closure_ty: Ty<'tcx>,
-                                             def: def::Def,
+                                             def_id: ast::DefId,
                                              fn_ptr: ValueRef)
                                              -> DatumBlock<'blk, 'tcx, Expr>  {
     let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust");
-    let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def, fn_ptr, true);
+    let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def_id, fn_ptr, true);
     fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p(bcx.ccx())));
 
     DatumBlock::new(bcx, scratch.to_expr_datum())
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 4f7d0f8fe75..bc386dc96a4 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -190,21 +190,24 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr)
         None => { }
         Some(adj) => {
             match adj {
-                ty::AdjustAddEnv(ty::RegionTraitStore(ty::ReStatic, _)) => {
-                    let def = ty::resolve_expr(cx.tcx(), e);
+                ty::AdjustAddEnv(def_id, ty::RegionTraitStore(ty::ReStatic, _)) => {
                     let wrapper = closure::get_wrapper_for_bare_fn(cx,
                                                                    ety_adjusted,
-                                                                   def,
+                                                                   def_id,
                                                                    llconst,
                                                                    true);
                     llconst = C_struct(cx, &[wrapper, C_null(Type::i8p(cx))], false)
                 }
-                ty::AdjustAddEnv(store) => {
+                ty::AdjustAddEnv(_, store) => {
                     cx.sess()
                       .span_bug(e.span,
                                 format!("unexpected static function: {}",
                                         store)[])
                 }
+                ty::AdjustReifyFnPointer(_def_id) => {
+                    // FIXME(#19925) once fn item types are
+                    // zero-sized, we'll need to do something here
+                }
                 ty::AdjustDerefRef(ref adj) => {
                     let mut ty = ety;
                     // Save the last autoderef in case we can avoid it.
diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs
index 2545de34ed8..adad2d50132 100644
--- a/src/librustc_trans/trans/debuginfo.rs
+++ b/src/librustc_trans/trans/debuginfo.rs
@@ -430,7 +430,7 @@ impl<'tcx> TypeMap<'tcx> {
                                        trait_data.principal.substs(),
                                        &mut unique_type_id);
             },
-            ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+            ty::ty_bare_fn(_, ty::BareFnTy{ unsafety, abi, ref sig } ) => {
                 if unsafety == ast::Unsafety::Unsafe {
                     unique_type_id.push_str("unsafe ");
                 }
@@ -2997,7 +2997,7 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::ty_bare_fn(ref barefnty) => {
+        ty::ty_bare_fn(_, ref barefnty) => {
             subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
         }
         ty::ty_closure(ref closurety) => {
@@ -3814,7 +3814,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_item_name(cx, trait_data.principal.def_id(), false, output);
             push_type_params(cx, trait_data.principal.substs(), output);
         },
-        ty::ty_bare_fn(ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+        ty::ty_bare_fn(_, ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == ast::Unsafety::Unsafe {
                 output.push_str("unsafe ");
             }
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index 36f23f4a0ca..3388a7623e3 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -54,7 +54,7 @@ use trans::inline;
 use trans::tvec;
 use trans::type_of;
 use middle::ty::{struct_fields, tup_fields};
-use middle::ty::{AdjustDerefRef, AdjustAddEnv, AutoUnsafe};
+use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustAddEnv, AutoUnsafe};
 use middle::ty::{AutoPtr};
 use middle::ty::{mod, Ty};
 use middle::ty::MethodCall;
@@ -177,8 +177,12 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            datum.to_string(bcx.ccx()),
            adjustment.repr(bcx.tcx()));
     match adjustment {
-        AdjustAddEnv(..) => {
-            datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
+        AdjustAddEnv(def_id, _) => {
+            datum = unpack_datum!(bcx, add_env(bcx, def_id, expr, datum));
+        }
+        AdjustReifyFnPointer(_def_id) => {
+            // FIXME(#19925) once fn item types are
+            // zero-sized, we'll need to do something here
         }
         AdjustDerefRef(ref adj) => {
             let (autoderefs, use_autoref) = match adj.autoref {
@@ -466,6 +470,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     fn add_env<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                           def_id: ast::DefId,
                            expr: &ast::Expr,
                            datum: Datum<'tcx, Expr>)
                            -> DatumBlock<'blk, 'tcx, Expr> {
@@ -477,8 +482,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         let closure_ty = expr_ty_adjusted(bcx, expr);
         let fn_ptr = datum.to_llscalarish(bcx);
-        let def = ty::resolve_expr(bcx.tcx(), expr);
-        closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
+        closure::make_closure_from_bare_fn(bcx, closure_ty, def_id, fn_ptr)
     }
 }
 
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index d7e3476a470..1bad476863f 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -228,7 +228,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
            ccx.tn().val_to_string(llretptr));
 
     let (fn_abi, fn_sig) = match callee_ty.sty {
-        ty::ty_bare_fn(ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
+        ty::ty_bare_fn(_, ref fn_ty) => (fn_ty.abi, fn_ty.sig.clone()),
         _ => ccx.sess().bug("trans_native_call called on non-function type")
     };
     let llsig = foreign_signature(ccx, &fn_sig, passed_arg_tys[]);
@@ -479,7 +479,7 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let tys = foreign_types_for_fn_ty(ccx, t);
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
     let cconv = match t.sty {
-        ty::ty_bare_fn(ref fn_ty) => {
+        ty::ty_bare_fn(_, ref fn_ty) => {
             llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
@@ -502,7 +502,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
     let t = ty::node_id_to_type(ccx.tcx(), node_id);
     let cconv = match t.sty {
-        ty::ty_bare_fn(ref fn_ty) => {
+        ty::ty_bare_fn(_, ref fn_ty) => {
             llvm_calling_convention(ccx, fn_ty.abi)
         }
         _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
@@ -556,7 +556,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // Compute the type that the function would have if it were just a
         // normal Rust function. This will be the type of the wrappee fn.
         match t.sty {
-            ty::ty_bare_fn(ref f) => {
+            ty::ty_bare_fn(_, ref f) => {
                 assert!(f.abi != Rust && f.abi != RustIntrinsic);
             }
             _ => {
@@ -849,7 +849,7 @@ fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
     let fn_sig = match ty.sty {
-        ty::ty_bare_fn(ref fn_ty) => fn_ty.sig.clone(),
+        ty::ty_bare_fn(_, ref fn_ty) => fn_ty.sig.clone(),
         _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
     };
     let llsig = foreign_signature(ccx, &fn_sig, fn_sig.0.inputs.as_slice());
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index c1089ea3ad1..26734d854af 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -226,7 +226,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
     let self_ty = match fty.sty {
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(_, ref f) => {
             assert!(f.sig.0.inputs.len() == 1);
             f.sig.0.inputs[0]
         }
@@ -289,6 +289,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         }
 
         let dtor_ty = ty::mk_ctor_fn(bcx.tcx(),
+                                     class_did,
                                      &[get_drop_glue_type(bcx.ccx(), t)],
                                      ty::mk_nil(bcx.tcx()));
         let (_, variant_cx) = invoke(variant_cx, dtor_addr, args[], dtor_ty, None, false);
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index cc506e409c5..fff89999d99 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -150,7 +150,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     let tcx = bcx.tcx();
 
     let ret_ty = match callee_ty.sty {
-        ty::ty_bare_fn(ref f) => f.sig.0.output,
+        ty::ty_bare_fn(_, ref f) => f.sig.0.output,
         _ => panic!("expected bare_fn in trans_intrinsic_call")
     };
     let foreign_item = tcx.map.expect_foreign_item(node);
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 25b8cefa68f..38c6b802d04 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -477,7 +477,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     debug!("(translating trait callee) loading method");
     // Replace the self type (&Self or Box<Self>) with an opaque pointer.
     let llcallee_ty = match callee_ty.sty {
-        ty::ty_bare_fn(ref f) if f.abi == Rust || f.abi == RustCall => {
+        ty::ty_bare_fn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
             type_of_rust_fn(ccx,
                             Some(Type::i8p(ccx)),
                             f.sig.0.inputs.slice_from(1),
@@ -639,7 +639,8 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                        m.repr(tcx),
                        substs.repr(tcx));
                 if m.generics.has_type_params(subst::FnSpace) ||
-                   ty::type_has_self(ty::mk_bare_fn(tcx, m.fty.clone())) {
+                    ty::type_has_self(ty::mk_bare_fn(tcx, None, m.fty.clone()))
+                {
                     debug!("(making impl vtable) method has self or type \
                             params: {}",
                            token::get_name(name));
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 2ef0006814a..499195b51b9 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -150,7 +150,9 @@ pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>)
                             f.sig.0.output,
                             f.abi)
         }
-        ty::ty_bare_fn(ref f) => {
+        ty::ty_bare_fn(_, ref f) => {
+            // FIXME(#19925) once fn item types are
+            // zero-sized, we'll need to do something here
             if f.abi == abi::Rust || f.abi == abi::RustCall {
                 type_of_rust_fn(cx,
                                 None,
@@ -364,7 +366,7 @@ pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
 
       ty::ty_str => Type::i8(cx),
 
-      ty::ty_bare_fn(_) => {
+      ty::ty_bare_fn(..) => {
           type_of_fn_from_ty(cx, t).ptr_to()
       }
       ty::ty_closure(_) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0bf984ef154..ff577d2d45d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -954,7 +954,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                     tcx.sess.span_err(ast_ty.span,
                                       "variadic function must have C calling convention");
                 }
-                ty::mk_bare_fn(tcx, ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl))
+                ty::mk_bare_fn(tcx, None, ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl))
             }
             ast::TyClosure(ref f) => {
                 // Use corresponding trait store to figure out default bounds
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 2c220f29826..d3b518ec2e3 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -113,7 +113,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         self.add_obligations(&pick, &method_bounds_substs, &method_bounds);
 
         // Create the final `MethodCallee`.
-        let fty = ty::mk_bare_fn(self.tcx(), ty::BareFnTy {
+        let fty = ty::mk_bare_fn(self.tcx(), None, ty::BareFnTy {
             sig: ty::Binder(method_sig),
             unsafety: pick.method_ty.fty.unsafety,
             abi: pick.method_ty.fty.abi.clone(),
@@ -466,7 +466,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
     fn fixup_derefs_on_method_receiver_if_necessary(&self,
                                                     method_callee: &MethodCallee) {
         let sig = match method_callee.ty.sty {
-            ty::ty_bare_fn(ref f) => f.sig.clone(),
+            ty::ty_bare_fn(_, ref f) => f.sig.clone(),
             ty::ty_closure(ref f) => f.sig.clone(),
             _ => return,
         };
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 74e690bf68f..19776318c87 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -199,7 +199,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>,
                                                                        infer::FnCall,
                                                                        &fn_sig).0;
     let transformed_self_ty = fn_sig.inputs[0];
-    let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+    let fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy {
         sig: ty::Binder(fn_sig),
         unsafety: bare_fn_ty.unsafety,
         abi: bare_fn_ty.abi.clone(),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7020ca4b542..3139a17f998 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -399,7 +399,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let fty = fty.subst(ccx.tcx, &param_env.free_substs);
 
     match fty.sty {
-        ty::ty_bare_fn(ref fn_ty) => {
+        ty::ty_bare_fn(_, ref fn_ty) => {
             let inh = Inherited::new(ccx.tcx, param_env);
             let fcx = check_fn(ccx, fn_ty.unsafety, id, &fn_ty.sig,
                                decl, id, body, &inh);
@@ -1132,9 +1132,9 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     }
 
     // Compute skolemized form of impl and trait method tys.
-    let impl_fty = ty::mk_bare_fn(tcx, impl_m.fty.clone());
+    let impl_fty = ty::mk_bare_fn(tcx, None, impl_m.fty.clone());
     let impl_fty = impl_fty.subst(tcx, &impl_to_skol_substs);
-    let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
+    let trait_fty = ty::mk_bare_fn(tcx, None, trait_m.fty.clone());
     let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
 
     // Check the impl method type IM is a subtype of the trait method
@@ -1389,6 +1389,8 @@ fn check_cast(fcx: &FnCtxt,
         }, t_e, None);
     }
 
+    let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
+
     let t_1_is_scalar = ty::type_is_scalar(t_1);
     let t_1_is_char = ty::type_is_char(t_1);
     let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
@@ -1396,7 +1398,9 @@ fn check_cast(fcx: &FnCtxt,
 
     // casts to scalars other than `char` and `bare fn` are trivial
     let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
-    if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial {
+    if t_e_is_bare_fn_item && t_1_is_bare_fn {
+        demand::coerce(fcx, e.span, t_1, &*e);
+    } else if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial {
         if t_1_is_float || ty::type_is_unsafe_ptr(t_1) {
             fcx.type_error_message(span, |actual| {
                 format!("illegal cast; cast through an \
@@ -1634,7 +1638,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                        span: Span,
                                        adj: &ty::AutoAdjustment<'tcx>) {
         match *adj {
-            ty::AdjustAddEnv(..) => { }
+            ty::AdjustAddEnv(..) |
+            ty::AdjustReifyFnPointer(..) => {
+            }
             ty::AdjustDerefRef(ref d_r) => {
                 match d_r.autoref {
                     Some(ref a_r) => {
@@ -2043,7 +2049,7 @@ fn try_overloaded_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Bail out if the callee is a bare function or a closure. We check those
     // manually.
     match structurally_resolved_type(fcx, callee.span, callee_type).sty {
-        ty::ty_bare_fn(_) | ty::ty_closure(_) => return false,
+        ty::ty_bare_fn(..) | ty::ty_closure(_) => return false,
         _ => {}
     }
 
@@ -2493,7 +2499,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         ty::FnConverging(ty::mk_err())
     } else {
         match method_fn_ty.sty {
-            ty::ty_bare_fn(ref fty) => {
+            ty::ty_bare_fn(_, ref fty) => {
                 // HACK(eddyb) ignore self in the definition (see above).
                 check_argument_types(fcx,
                                      sp,
@@ -2921,7 +2927,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         });
 
         let fn_sig = match fn_ty.sty {
-            ty::ty_bare_fn(ty::BareFnTy {ref sig, ..}) |
+            ty::ty_bare_fn(_, ty::BareFnTy {ref sig, ..}) |
             ty::ty_closure(box ty::ClosureTy {ref sig, ..}) => sig,
             _ => {
                 fcx.type_error_message(call_expr.span, |actual| {
@@ -3875,7 +3881,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
         }
 
         let lhs_ty = fcx.expr_ty(&**lhs);
-        check_expr_has_type(fcx, &**rhs, lhs_ty);
+        check_expr_coercable_to_type(fcx, &**rhs, lhs_ty);
         let rhs_ty = fcx.expr_ty(&**rhs);
 
         fcx.require_expr_have_sized_type(&**lhs, traits::AssignmentLhsSized);
@@ -5641,7 +5647,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) {
         };
         (n_tps, inputs, ty::FnConverging(output))
     };
-    let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+    let fty = ty::mk_bare_fn(tcx, None, ty::BareFnTy {
         unsafety: ast::Unsafety::Unsafe,
         abi: abi::RustIntrinsic,
         sig: ty::Binder(FnSig {
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 24d7bf5031e..a2fb44fff79 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -355,7 +355,7 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
 
                 self.fold_substs(substs);
             }
-            ty::ty_bare_fn(ty::BareFnTy{sig: ref fn_sig, ..}) |
+            ty::ty_bare_fn(_, ty::BareFnTy{sig: ref fn_sig, ..}) |
             ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => {
                 self.binding_count += 1;
 
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 700d1211606..b123d97d897 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -15,7 +15,6 @@ use self::ResolveReason::*;
 
 use astconv::AstConv;
 use check::FnCtxt;
-use middle::def;
 use middle::pat_util;
 use middle::ty::{mod, Ty, MethodCall, MethodCallee};
 use middle::ty_fold::{TypeFolder,TypeFoldable};
@@ -267,25 +266,12 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             Some(adjustment) => {
                 let adj_object = ty::adjust_is_object(&adjustment);
                 let resolved_adjustment = match adjustment {
-                    ty::AdjustAddEnv(store) => {
-                        // FIXME(eddyb) #2190 Allow only statically resolved
-                        // bare functions to coerce to a closure to avoid
-                        // constructing (slower) indirect call wrappers.
-                        match self.tcx().def_map.borrow().get(&id) {
-                            Some(&def::DefFn(..)) |
-                            Some(&def::DefStaticMethod(..)) |
-                            Some(&def::DefVariant(..)) |
-                            Some(&def::DefStruct(_)) => {
-                            }
-                            _ => {
-                                span_err!(self.tcx().sess, reason.span(self.tcx()), E0100,
-                                    "cannot coerce non-statically resolved bare fn to closure");
-                                span_help!(self.tcx().sess, reason.span(self.tcx()),
-                                    "consider embedding the function in a closure");
-                            }
-                        }
+                    ty::AdjustAddEnv(def_id, store) => {
+                        ty::AdjustAddEnv(def_id, self.resolve(&store, reason))
+                    }
 
-                        ty::AdjustAddEnv(self.resolve(&store, reason))
+                    ty::AdjustReifyFnPointer(def_id) => {
+                        ty::AdjustReifyFnPointer(def_id)
                     }
 
                     ty::AdjustDerefRef(adj) => {
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index c08eeb6e13e..b08db39c189 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -235,7 +235,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             // impl, plus its own.
             let new_polytype = ty::Polytype {
                 generics: new_method_ty.generics.clone(),
-                ty: ty::mk_bare_fn(tcx, new_method_ty.fty.clone())
+                ty: ty::mk_bare_fn(tcx, Some(new_did), new_method_ty.fty.clone())
             };
             debug!("new_polytype={}", new_polytype.repr(tcx));
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 22c9a2e7b32..c7c33db5746 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -211,6 +211,8 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     // Create a set of parameter types shared among all the variants.
     for variant in variants.iter() {
+        let variant_def_id = local_def(variant.node.id);
+
         // Nullary enum constructors get turned into constants; n-ary enum
         // constructors get turned into functions.
         let result_ty = match variant.node.kind {
@@ -246,7 +248,7 @@ pub fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             ty: result_ty
         };
 
-        tcx.tcache.borrow_mut().insert(local_def(variant.node.id), pty);
+        tcx.tcache.borrow_mut().insert(variant_def_id, pty);
 
         write_ty_to_tcx(tcx, variant.node.id, result_ty);
     }
@@ -353,7 +355,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             m.def_id,
             Polytype {
                 generics: m.generics.clone(),
-                ty: ty::mk_bare_fn(ccx.tcx, m.fty.clone()) });
+                ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), m.fty.clone()) });
     }
 
     fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -519,6 +521,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
             tcx.sess.span_err(m.span, "duplicate method in trait impl");
         }
 
+        let m_def_id = local_def(m.id);
         let mty = Rc::new(ty_of_method(ccx,
                                        convert_method_context,
                                        container,
@@ -526,13 +529,13 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
                                        untransformed_rcvr_ty,
                                        rcvr_ty_generics,
                                        rcvr_visibility));
-        let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
+        let fty = ty::mk_bare_fn(tcx, Some(m_def_id), mty.fty.clone());
         debug!("method {} (id {}) has type {}",
                 m.pe_ident().repr(tcx),
                 m.id,
                 fty.repr(tcx));
         tcx.tcache.borrow_mut().insert(
-            local_def(m.id),
+            m_def_id,
             Polytype {
                 generics: mty.generics.clone(),
                 ty: fty
@@ -1461,7 +1464,7 @@ pub fn ty_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
             };
             let pty = Polytype {
                 generics: ty_generics,
-                ty: ty::mk_bare_fn(ccx.tcx, tofd)
+                ty: ty::mk_bare_fn(ccx.tcx, Some(local_def(it.id)), tofd)
             };
             debug!("type of {} (id {}) is {}",
                     token::get_ident(it.ident),
@@ -2138,6 +2141,7 @@ pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let t_fn = ty::mk_bare_fn(
         ccx.tcx,
+        None,
         ty::BareFnTy {
             abi: abi,
             unsafety: ast::Unsafety::Unsafe,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 5a8f58274cc..65dff774528 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -102,6 +102,7 @@ use util::ppaux;
 use syntax::codemap::Span;
 use syntax::print::pprust::*;
 use syntax::{ast, ast_map, abi};
+use syntax::ast_util::local_def;
 
 #[cfg(stage0)]
 mod diagnostics;
@@ -224,7 +225,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 }
                 _ => ()
             }
-            let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(main_id)), ty::BareFnTy {
                 unsafety: ast::Unsafety::Normal,
                 abi: abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -256,7 +257,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
     let tcx = ccx.tcx;
     let start_t = ty::node_id_to_type(tcx, start_id);
     match start_t.sty {
-        ty::ty_bare_fn(_) => {
+        ty::ty_bare_fn(..) => {
             match tcx.map.find(start_id) {
                 Some(ast_map::NodeItem(it)) => {
                     match it.node {
@@ -272,7 +273,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
 
-            let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy {
+            let se_ty = ty::mk_bare_fn(tcx, Some(local_def(start_id)), ty::BareFnTy {
                 unsafety: ast::Unsafety::Normal,
                 abi: abi::Rust,
                 sig: ty::Binder(ty::FnSig {
diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs
index 754294a3b8e..8e69bc42d9a 100644
--- a/src/librustc_typeck/variance.rs
+++ b/src/librustc_typeck/variance.rs
@@ -814,12 +814,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
             }
 
-            ty::ty_bare_fn(ty::BareFnTy { ref sig, .. }) |
+            ty::ty_bare_fn(_, ty::BareFnTy { ref sig, .. }) |
             ty::ty_closure(box ty::ClosureTy {
                     ref sig,
                     store: ty::UniqTraitStore,
                     ..
-                }) => {
+                }) =>
+            {
                 self.add_constraints_from_sig(sig, variance);
             }
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d0988af1cb4..2bc93ade777 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -176,7 +176,7 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
 fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function {
     let t = ty::lookup_item_type(tcx, did);
     let (decl, style) = match t.ty.sty {
-        ty::ty_bare_fn(ref f) => ((did, &f.sig).clean(cx), f.unsafety),
+        ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety),
         _ => panic!("bad function"),
     };
     clean::Function {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ed2b85a34a9..0dd6c2a7ce7 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1360,7 +1360,7 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::ty_bare_fn(ref fty) => BareFunction(box BareFunctionDecl {
+            ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
                 unsafety: fty.unsafety,
                 generics: Generics {
                     lifetimes: Vec::new(),
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 5581874ea3a..f7984b8973c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -65,17 +65,21 @@ const HOEDOWN_EXTENSIONS: libc::c_uint =
 
 type hoedown_document = libc::c_void;  // this is opaque to us
 
+type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
+                                 *const hoedown_buffer, *mut libc::c_void);
+
+type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
+                              libc::c_int, *mut libc::c_void);
+
 #[repr(C)]
 struct hoedown_renderer {
     opaque: *mut hoedown_html_renderer_state,
-    blockcode: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                    *const hoedown_buffer, *mut libc::c_void)>,
+    blockcode: Option<blockcodefn>,
     blockquote: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
                                      *mut libc::c_void)>,
     blockhtml: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
                                     *mut libc::c_void)>,
-    header: Option<extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
-                                 libc::c_int, *mut libc::c_void)>,
+    header: Option<headerfn>,
     other: [libc::size_t, ..28],
 }
 
@@ -281,8 +285,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
             toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
         };
         (*(*renderer).opaque).opaque = &mut opaque as *mut _ as *mut libc::c_void;
-        (*renderer).blockcode = Some(block);
-        (*renderer).header = Some(header);
+        (*renderer).blockcode = Some(block as blockcodefn);
+        (*renderer).header = Some(header as headerfn);
 
         let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
         hoedown_document_render(document, ob, s.as_ptr(),
@@ -354,8 +358,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
     unsafe {
         let ob = hoedown_buffer_new(DEF_OUNIT);
         let renderer = hoedown_html_renderer_new(0, 0);
-        (*renderer).blockcode = Some(block);
-        (*renderer).header = Some(header);
+        (*renderer).blockcode = Some(block as blockcodefn);
+        (*renderer).header = Some(header as headerfn);
         (*(*renderer).opaque).opaque = tests as *mut _ as *mut libc::c_void;
 
         let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 692f120737a..d749cd77cef 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -838,8 +838,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     /// }
     /// ```
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
-    pub fn keys(&self) -> Keys<K, V> {
+    pub fn keys<'a>(&'a self) -> Keys<'a, K, V> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((&'a K,&'a V)) -> &'a K = first; // coerce to fn ptr
 
         Keys { inner: self.iter().map(first) }
     }
@@ -862,8 +863,9 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     /// }
     /// ```
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
-    pub fn values(&self) -> Values<K, V> {
+    pub fn values<'a>(&'a self) -> Values<'a, K, V> {
         fn second<A, B>((_, b): (A, B)) -> B { b }
+        let second: fn((&'a K,&'a V)) -> &'a V = second; // coerce to fn ptr
 
         Values { inner: self.iter().map(second) }
     }
@@ -938,6 +940,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn into_iter(self) -> IntoIter<K, V> {
         fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
+        let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two;
 
         IntoIter {
             inner: self.table.into_iter().map(last_two)
@@ -1007,6 +1010,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn drain(&mut self) -> Drain<K, V> {
         fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
+        let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; // coerce to fn pointer
 
         Drain {
             inner: self.table.drain().map(last_two),
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index 3d5be042963..6d83d5510b3 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -276,6 +276,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn into_iter(self) -> IntoIter<T> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((T, ())) -> T = first;
 
         IntoIter { iter: self.map.into_iter().map(first) }
     }
@@ -418,6 +419,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
     #[unstable = "matches collection reform specification, waiting for dust to settle"]
     pub fn drain(&mut self) -> Drain<T> {
         fn first<A, B>((a, _): (A, B)) -> A { a }
+        let first: fn((T, ())) -> T = first; // coerce to fn pointer
+
         Drain { iter: self.map.drain().map(first) }
     }
 
diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs
index a514837492a..f0a00b421c3 100644
--- a/src/libstd/path/posix.rs
+++ b/src/libstd/path/posix.rs
@@ -390,6 +390,7 @@ impl Path {
         let v = if self.repr[0] == SEP_BYTE {
             self.repr[1..]
         } else { self.repr.as_slice() };
+        let is_sep_byte: fn(&u8) -> bool = is_sep_byte; // coerce to fn ptr
         let mut ret = v.split(is_sep_byte);
         if v.is_empty() {
             // consume the empty "" component
@@ -404,7 +405,8 @@ impl Path {
         fn from_utf8(s: &[u8]) -> Option<&str> {
             str::from_utf8(s).ok()
         }
-        self.components().map(from_utf8)
+        let f: fn(&[u8]) -> Option<&str> = from_utf8; // coerce to fn ptr
+        self.components().map(f)
     }
 }
 
diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs
index 277c675c22d..b24966241ff 100644
--- a/src/libstd/path/windows.rs
+++ b/src/libstd/path/windows.rs
@@ -651,7 +651,8 @@ impl Path {
             None if repr.as_bytes()[0] == SEP_BYTE => repr[1..],
             None => repr
         };
-        let ret = s.split_terminator(SEP).map(Some);
+        let some: fn(&'a str) -> Option<&'a str> = Some; // coerce to fn ptr
+        let ret = s.split_terminator(SEP).map(some);
         ret
     }
 
@@ -662,6 +663,7 @@ impl Path {
             #![inline]
             x.unwrap().as_bytes()
         }
+        let convert: for<'b> fn(Option<&'b str>) -> &'b [u8] = convert; // coerce to fn ptr
         self.str_components().map(convert)
     }
 
@@ -1044,7 +1046,11 @@ fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
 
 // None result means the string didn't need normalizing
 fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
-    let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
+    let f: fn(char) -> bool = if !prefix_is_verbatim(prefix) {
+        is_sep
+    } else {
+        is_sep_verbatim
+    };
     let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
     let s_ = s[prefix_len(prefix)..];
     let s_ = if is_abs { s_[1..] } else { s_ };
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index 4c33d1c418d..04718dcc6ae 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -189,11 +189,12 @@ macro_rules! __thread_local_inner {
             }
         };
 
-        #[cfg(not(any(target_os = "macos", target_os = "linux")))]
+        #[cfg(all(stage0, not(any(target_os = "macos", target_os = "linux"))))]
         const INIT: ::std::thread_local::KeyInner<$t> = {
             unsafe extern fn __destroy(ptr: *mut u8) {
                 ::std::thread_local::destroy_value::<$t>(ptr);
             }
+
             ::std::thread_local::KeyInner {
                 inner: ::std::cell::UnsafeCell { value: $init },
                 os: ::std::thread_local::OsStaticKey {
@@ -203,6 +204,21 @@ macro_rules! __thread_local_inner {
             }
         };
 
+        #[cfg(all(not(stage0), not(any(target_os = "macos", target_os = "linux"))))]
+        const INIT: ::std::thread_local::KeyInner<$t> = {
+            unsafe extern fn __destroy(ptr: *mut u8) {
+                ::std::thread_local::destroy_value::<$t>(ptr);
+            }
+
+            ::std::thread_local::KeyInner {
+                inner: ::std::cell::UnsafeCell { value: $init },
+                os: ::std::thread_local::OsStaticKey {
+                    inner: ::std::thread_local::OS_INIT_INNER,
+                    dtor: ::std::option::Option::Some(__destroy as unsafe extern fn(*mut u8)),
+                },
+            }
+        };
+
         INIT
     });
 }
@@ -323,6 +339,12 @@ mod imp {
         // *should* be the case that this loop always terminates because we
         // provide the guarantee that a TLS key cannot be set after it is
         // flagged for destruction.
+        #[cfg(not(stage0))]
+        static DTORS: os::StaticKey = os::StaticKey {
+            inner: os::INIT_INNER,
+            dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)),
+        };
+        #[cfg(stage0)]
         static DTORS: os::StaticKey = os::StaticKey {
             inner: os::INIT_INNER,
             dtor: Some(run_dtors),
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 62fe718b522..d45871708dc 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -50,14 +50,16 @@ pub trait ItemDecorator {
               push: |P<ast::Item>|);
 }
 
-impl ItemDecorator for fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, |P<ast::Item>|) {
+impl<F> ItemDecorator for F
+    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, |P<ast::Item>|)
+{
     fn expand(&self,
               ecx: &mut ExtCtxt,
               sp: Span,
               meta_item: &ast::MetaItem,
               item: &ast::Item,
               push: |P<ast::Item>|) {
-        self.clone()(ecx, sp, meta_item, item, push)
+        (*self)(ecx, sp, meta_item, item, push)
     }
 }
 
@@ -70,14 +72,16 @@ pub trait ItemModifier {
               -> P<ast::Item>;
 }
 
-impl ItemModifier for fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item> {
+impl<F> ItemModifier for F
+    where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item>
+{
     fn expand(&self,
               ecx: &mut ExtCtxt,
               span: Span,
               meta_item: &ast::MetaItem,
               item: P<ast::Item>)
               -> P<ast::Item> {
-        self.clone()(ecx, span, meta_item, item)
+        (*self)(ecx, span, meta_item, item)
     }
 }
 
@@ -93,13 +97,15 @@ pub trait TTMacroExpander {
 pub type MacroExpanderFn =
     for<'cx> fn(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box<MacResult+'cx>;
 
-impl TTMacroExpander for MacroExpanderFn {
+impl<F> TTMacroExpander for F
+    where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box<MacResult+'cx>
+{
     fn expand<'cx>(&self,
                    ecx: &'cx mut ExtCtxt,
                    span: Span,
                    token_tree: &[ast::TokenTree])
                    -> Box<MacResult+'cx> {
-        self.clone()(ecx, span, token_tree)
+        (*self)(ecx, span, token_tree)
     }
 }
 
@@ -115,14 +121,18 @@ pub trait IdentMacroExpander {
 pub type IdentMacroExpanderFn =
     for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult+'cx>;
 
-impl IdentMacroExpander for IdentMacroExpanderFn {
+impl<F> IdentMacroExpander for F
+    where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, ast::Ident,
+                          Vec<ast::TokenTree>) -> Box<MacResult+'cx>
+{
     fn expand<'cx>(&self,
                    cx: &'cx mut ExtCtxt,
                    sp: Span,
                    ident: ast::Ident,
                    token_tree: Vec<ast::TokenTree> )
-                   -> Box<MacResult+'cx> {
-        self.clone()(cx, sp, ident, token_tree)
+                   -> Box<MacResult+'cx>
+    {
+        (*self)(cx, sp, ident, token_tree)
     }
 }
 
diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs
index 7d59e3de7b1..65b8ad997f6 100644
--- a/src/libunicode/u_str.rs
+++ b/src/libunicode/u_str.rs
@@ -64,7 +64,10 @@ impl UnicodeStr for str {
     #[inline]
     fn words(&self) -> Words {
         fn is_not_empty(s: &&str) -> bool { !s.is_empty() }
+        let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer
+
         fn is_whitespace(c: char) -> bool { c.is_whitespace() }
+        let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer
 
         Words { inner: self.split(is_whitespace).filter(is_not_empty) }
     }
diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs
index 8c6e76e7746..1b4e5891f94 100644
--- a/src/test/compile-fail/borrowck-autoref-3261.rs
+++ b/src/test/compile-fail/borrowck-autoref-3261.rs
@@ -20,7 +20,7 @@ impl X {
 }
 
 fn main() {
-    let mut x = X(Either::Right(main));
+    let mut x = X(Either::Right(main as fn()));
     (&mut x).with(
         |opt| { //~ ERROR cannot borrow `x` as mutable more than once at a time
             match opt {
diff --git a/src/test/compile-fail/cast-to-bare-fn.rs b/src/test/compile-fail/cast-to-bare-fn.rs
index 10a829fd794..1db813292b0 100644
--- a/src/test/compile-fail/cast-to-bare-fn.rs
+++ b/src/test/compile-fail/cast-to-bare-fn.rs
@@ -13,7 +13,7 @@ fn foo(_x: int) { }
 fn main() {
     let v: u64 = 5;
     let x = foo as extern "C" fn() -> int;
-    //~^ ERROR non-scalar cast
+    //~^ ERROR mismatched types
     let y = v as extern "Rust" fn(int) -> (int, int);
     //~^ ERROR non-scalar cast
     y(x());
diff --git a/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs b/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs
index 27e339180a6..52f4c4749e2 100644
--- a/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs
+++ b/src/test/compile-fail/coerce-bare-fn-to-closure-and-proc.rs
@@ -8,12 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// Test that coercions from fn item types are ok, but not fn pointer
+// types to closures/procs are not allowed.
+
 fn foo() {}
 
-fn main() {
+fn fn_item_type() {
     let f = foo;
 
     let f_closure: || = f;
-    //~^ ERROR: cannot coerce non-statically resolved bare fn to closure
-    //~^^ HELP: consider embedding the function in a closure
 }
+
+fn fn_pointer_type() {
+    let f = foo as fn();
+    let f_closure: || = f;
+    //~^ ERROR: mismatched types
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs
new file mode 100644
index 00000000000..dd4a24bfb2f
--- /dev/null
+++ b/src/test/compile-fail/fn-item-type.rs
@@ -0,0 +1,25 @@
+// 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 the types of distinct fn items are not compatible by
+// default. See also `run-pass/fn-item-type-*.rs`.
+
+fn foo(x: int) -> int { x * 2 }
+fn bar(x: int) -> int { x * 4 }
+
+fn eq<T>(x: T, y: T) { }
+
+fn main() {
+    let f = if true { foo } else { bar };
+    //~^ ERROR expected fn item, found a different fn item
+
+    eq(foo, bar);
+    //~^ ERROR expected fn item, found a different fn item
+}
diff --git a/src/test/compile-fail/issue-10764.rs b/src/test/compile-fail/issue-10764.rs
index 0733744b652..cd4ec495556 100644
--- a/src/test/compile-fail/issue-10764.rs
+++ b/src/test/compile-fail/issue-10764.rs
@@ -12,4 +12,4 @@ fn f(_: extern "Rust" fn()) {}
 extern fn bar() {}
 
 fn main() { f(bar) }
-//~^ ERROR: expected `fn()`, found `extern "C" fn()`
+//~^ ERROR mismatched types
diff --git a/src/test/compile-fail/issue-9575.rs b/src/test/compile-fail/issue-9575.rs
index aa3d9d9fef0..6e8f7ffb68d 100644
--- a/src/test/compile-fail/issue-9575.rs
+++ b/src/test/compile-fail/issue-9575.rs
@@ -10,6 +10,6 @@
 
 #[start]
 fn start(argc: int, argv: *const *const u8, crate_map: *const u8) -> int {
-    //~^ ERROR start function expects type: `fn(int, *const *const u8) -> int`
+    //~^ ERROR incorrect number of function parameters
     0
 }
diff --git a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
index 381144f2599..3e6a95b04f7 100644
--- a/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
+++ b/src/test/compile-fail/region-lifetime-bounds-on-fns-where-clause.rs
@@ -15,7 +15,7 @@ fn a<'a, 'b>(x: &mut &'a int, y: &mut &'b int) where 'b: 'a {
 
 fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR mismatched types
+    *x = *y; //~ ERROR cannot infer
 }
 
 fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) {
diff --git a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
index a03911e1d0e..2d635e9fc27 100644
--- a/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
+++ b/src/test/compile-fail/region-multiple-lifetime-bounds-on-fns-where-clause.rs
@@ -16,8 +16,8 @@ fn a<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) where 'b: 'a
 
 fn b<'a, 'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR mismatched types
-    *z = *y; //~ ERROR mismatched types
+    *x = *y; //~ ERROR cannot infer
+    *z = *y; //~ ERROR cannot infer
 }
 
 fn c<'a,'b, 'c>(x: &mut &'a int, y: &mut &'b int, z: &mut &'c int) {
diff --git a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
index 773d6e2c703..4a42728da6f 100644
--- a/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
+++ b/src/test/compile-fail/regions-lifetime-bounds-on-fns.rs
@@ -15,7 +15,7 @@ fn a<'a, 'b:'a>(x: &mut &'a int, y: &mut &'b int) {
 
 fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) {
     // Illegal now because there is no `'b:'a` declaration.
-    *x = *y; //~ ERROR mismatched types
+    *x = *y; //~ ERROR cannot infer
 }
 
 fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) {
diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs
index cf0b615bb01..f4654367970 100644
--- a/src/test/compile-fail/regions-nested-fns.rs
+++ b/src/test/compile-fail/regions-nested-fns.rs
@@ -12,10 +12,10 @@ fn ignore<T>(t: T) {}
 
 fn nested<'x>(x: &'x int) {
     let y = 3;
-    let mut ay = &y; //~ ERROR cannot infer
+    let mut ay = &y;
 
     ignore::< for<'z>|&'z int|>(|z| {
-        ay = x;
+        ay = x; //~ ERROR cannot infer
         ay = &y;
         ay = z;
     });
diff --git a/src/test/compile-fail/static-reference-to-fn-1.rs b/src/test/compile-fail/static-reference-to-fn-1.rs
index c0d430908a1..bce397c4793 100644
--- a/src/test/compile-fail/static-reference-to-fn-1.rs
+++ b/src/test/compile-fail/static-reference-to-fn-1.rs
@@ -24,7 +24,7 @@ fn foo() -> Option<int> {
 
 fn create() -> A<'static> {
     A {
-        func: &foo, //~ ERROR borrowed value does not live long enough
+        func: &foo, //~ ERROR mismatched types
     }
 }
 
diff --git a/src/test/compile-fail/static-reference-to-fn-2.rs b/src/test/compile-fail/static-reference-to-fn-2.rs
index 3a0f0a193cf..d7255c3ba06 100644
--- a/src/test/compile-fail/static-reference-to-fn-2.rs
+++ b/src/test/compile-fail/static-reference-to-fn-2.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 
 struct StateMachineIter<'a> {
-    statefn: &'a fn(&mut StateMachineIter<'a>) -> Option<&'static str>
+    statefn: &'a StateMachineFunc<'a>
 }
 
+type StateMachineFunc<'a> = fn(&mut StateMachineIter<'a>) -> Option<&'static str>;
+
 impl<'a> Iterator<&'static str> for StateMachineIter<'a> {
     fn next(&mut self) -> Option<&'static str> {
         return  (*self.statefn)(self);
@@ -19,19 +21,19 @@ impl<'a> Iterator<&'static str> for StateMachineIter<'a> {
 }
 
 fn state1(self_: &mut StateMachineIter) -> Option<&'static str> {
-    self_.statefn = &state2;
+    self_.statefn = &(state2 as StateMachineFunc);
     //~^ ERROR borrowed value does not live long enough
     return Some("state1");
 }
 
 fn state2(self_: &mut StateMachineIter) -> Option<(&'static str)> {
-    self_.statefn = &state3;
+    self_.statefn = &(state3 as StateMachineFunc);
     //~^ ERROR borrowed value does not live long enough
     return Some("state2");
 }
 
 fn state3(self_: &mut StateMachineIter) -> Option<(&'static str)> {
-    self_.statefn = &finished;
+    self_.statefn = &(finished as StateMachineFunc);
     //~^ ERROR borrowed value does not live long enough
     return Some("state3");
 }
@@ -42,7 +44,7 @@ fn finished(_: &mut StateMachineIter) -> Option<(&'static str)> {
 
 fn state_iter() -> StateMachineIter<'static> {
     StateMachineIter {
-        statefn: &state1 //~ ERROR borrowed value does not live long enough
+        statefn: &(state1 as StateMachineFunc) //~ ERROR borrowed value does not live long enough
     }
 }
 
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 974af1e6f3e..e4389cd69dd 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -50,20 +50,20 @@ pub fn bar() {
 
 
              ((::std::fmt::format as
-                  fn(&core::fmt::Arguments<'_>) -> collections::string::String)((&((::std::fmt::Arguments::new
-                                                                                       as
-                                                                                       fn(&[&str], &[core::fmt::Argument<'_>]) -> core::fmt::Arguments<'_>)((__STATIC_FMTSTR
-                                                                                                                                                                as
-                                                                                                                                                                &'static [&'static str]),
-                                                                                                                                                            (&([]
-                                                                                                                                                                  as
-                                                                                                                                                                  [core::fmt::Argument<'_>; 0])
-                                                                                                                                                                as
-                                                                                                                                                                &[core::fmt::Argument<'_>; 0]))
-                                                                                      as
-                                                                                      core::fmt::Arguments<'_>)
-                                                                                    as
-                                                                                    &core::fmt::Arguments<'_>))
+                  fn(&core::fmt::Arguments<'_>) -> collections::string::String {std::fmt::format})((&((::std::fmt::Arguments::new
+                                                                                                          as
+                                                                                                          fn(&[&str], &[core::fmt::Argument<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a>::new})((__STATIC_FMTSTR
+                                                                                                                                                                                                                   as
+                                                                                                                                                                                                                   &'static [&'static str]),
+                                                                                                                                                                                                               (&([]
+                                                                                                                                                                                                                     as
+                                                                                                                                                                                                                     [core::fmt::Argument<'_>; 0])
+                                                                                                                                                                                                                   as
+                                                                                                                                                                                                                   &[core::fmt::Argument<'_>; 0]))
+                                                                                                         as
+                                                                                                         core::fmt::Arguments<'_>)
+                                                                                                       as
+                                                                                                       &core::fmt::Arguments<'_>))
                  as collections::string::String)
          }
      } as collections::string::String);
@@ -78,7 +78,8 @@ pub fn id<T>(x: T) -> T { (x as T) }
 pub fn use_id() {
     let _ =
         ((id::<[int; (3u as uint)]> as
-             fn([int; 3]) -> [int; 3])(([(1 as int), (2 as int), (3 as int)]
-                                           as [int; 3])) as [int; 3]);
+             fn([int; 3]) -> [int; 3] {id})(([(1 as int), (2 as int),
+                                              (3 as int)] as [int; 3])) as
+            [int; 3]);
 }
 fn main() { }
diff --git a/src/test/run-pass/const-extern-function.rs b/src/test/run-pass/const-extern-function.rs
index be7c47dafc0..069ca6ecf49 100644
--- a/src/test/run-pass/const-extern-function.rs
+++ b/src/test/run-pass/const-extern-function.rs
@@ -18,6 +18,6 @@ struct S {
 }
 
 pub fn main() {
-    assert!(foopy == f);
+    assert!(foopy as extern "C" fn() == f);
     assert!(f == s.f);
 }
diff --git a/src/test/run-pass/extern-compare-with-return-type.rs b/src/test/run-pass/extern-compare-with-return-type.rs
index 057394b2624..3febff18704 100644
--- a/src/test/run-pass/extern-compare-with-return-type.rs
+++ b/src/test/run-pass/extern-compare-with-return-type.rs
@@ -18,15 +18,17 @@ extern fn uintret() -> uint { 22 }
 extern fn uintvoidret(_x: uint) {}
 
 extern fn uintuintuintuintret(x: uint, y: uint, z: uint) -> uint { x+y+z }
+type uintuintuintuintret = extern fn(uint,uint,uint) -> uint;
 
 pub fn main() {
-    assert!(voidret1 == voidret1);
-    assert!(voidret1 != voidret2);
+    assert!(voidret1 as extern fn() == voidret1 as extern fn());
+    assert!(voidret1 as extern fn() != voidret2 as extern fn());
 
-    assert!(uintret == uintret);
+    assert!(uintret as extern fn() -> uint == uintret as extern fn() -> uint);
 
-    assert!(uintvoidret == uintvoidret);
+    assert!(uintvoidret as extern fn(uint) == uintvoidret as extern fn(uint));
 
-    assert!(uintuintuintuintret == uintuintuintuintret);
+    assert!(uintuintuintuintret as uintuintuintuintret ==
+            uintuintuintuintret as uintuintuintuintret);
 }
 
diff --git a/src/test/run-pass/fn-item-type-cast.rs b/src/test/run-pass/fn-item-type-cast.rs
new file mode 100644
index 00000000000..bfd02f5e27b
--- /dev/null
+++ b/src/test/run-pass/fn-item-type-cast.rs
@@ -0,0 +1,28 @@
+// 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 explicit coercions from a fn item type to a fn pointer type.
+
+fn foo(x: int) -> int { x * 2 }
+fn bar(x: int) -> int { x * 4 }
+type IntMap = fn(int) -> int;
+
+fn eq<T>(x: T, y: T) { }
+
+static TEST: Option<IntMap> = Some(foo as IntMap);
+
+fn main() {
+    let f = foo as IntMap;
+
+    let f = if true { foo as IntMap } else { bar as IntMap };
+    assert_eq!(f(4), 8);
+
+    eq(foo as IntMap, bar as IntMap);
+}
diff --git a/src/test/run-pass/fn-item-type-coerce.rs b/src/test/run-pass/fn-item-type-coerce.rs
new file mode 100644
index 00000000000..8427a0f4446
--- /dev/null
+++ b/src/test/run-pass/fn-item-type-coerce.rs
@@ -0,0 +1,23 @@
+// 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 implicit coercions from a fn item type to a fn pointer type.
+
+fn foo(x: int) -> int { x * 2 }
+fn bar(x: int) -> int { x * 4 }
+type IntMap = fn(int) -> int;
+
+fn eq<T>(x: T, y: T) { }
+
+fn main() {
+    let f: IntMap = foo;
+
+    eq::<IntMap>(foo, bar);
+}
diff --git a/src/test/run-pass/issue-10767.rs b/src/test/run-pass/issue-10767.rs
index a30eb8120ea..d2895024187 100644
--- a/src/test/run-pass/issue-10767.rs
+++ b/src/test/run-pass/issue-10767.rs
@@ -12,5 +12,5 @@
 pub fn main() {
     fn f() {
     };
-    let _: Box<fn()> = box f;
+    let _: Box<fn()> = box() (f as fn());
 }
diff --git a/src/test/run-pass/issue-15444.rs b/src/test/run-pass/issue-15444.rs
index f5618c2c7a3..0f4978d78dd 100644
--- a/src/test/run-pass/issue-15444.rs
+++ b/src/test/run-pass/issue-15444.rs
@@ -25,5 +25,6 @@ fn thing(a: int, b: int) -> int {
 }
 
 fn main() {
+    let thing: fn(int, int) -> int = thing; // coerce to fn type
     bar(&thing);
 }