about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/grammar/parser-lalr.y23
-rw-r--r--src/librustc/metadata/csearch.rs7
-rw-r--r--src/librustc/metadata/decoder.rs62
-rw-r--r--src/librustc/metadata/encoder.rs83
-rw-r--r--src/librustc/middle/check_const.rs33
-rw-r--r--src/librustc/middle/check_match.rs15
-rw-r--r--src/librustc/middle/check_static_recursion.rs112
-rw-r--r--src/librustc/middle/const_eval.rs161
-rw-r--r--src/librustc/middle/ty.rs49
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs14
-rw-r--r--src/librustc_driver/pretty.rs24
-rw-r--r--src/librustc_lint/builtin.rs21
-rw-r--r--src/librustc_privacy/lib.rs45
-rw-r--r--src/librustc_resolve/lib.rs42
-rw-r--r--src/librustc_trans/save/mod.rs33
-rw-r--r--src/librustc_trans/trans/consts.rs16
-rw-r--r--src/librustc_typeck/check/compare_method.rs82
-rw-r--r--src/librustc_typeck/check/method/confirm.rs23
-rw-r--r--src/librustc_typeck/check/method/mod.rs17
-rw-r--r--src/librustc_typeck/check/method/probe.rs276
-rw-r--r--src/librustc_typeck/check/mod.rs123
-rw-r--r--src/librustc_typeck/collect.rs70
-rw-r--r--src/librustc_typeck/diagnostics.rs5
-rw-r--r--src/librustdoc/clean/inline.rs29
-rw-r--r--src/librustdoc/html/render.rs24
-rw-r--r--src/libsyntax/parse/parser.rs26
-rw-r--r--src/libsyntax/print/pprust.rs30
-rw-r--r--src/test/compile-fail/associated-const-private-impl.rs27
-rw-r--r--src/test/compile-fail/impl-type-where-trait-has-method.rs21
-rw-r--r--src/test/parse-fail/issue-20711-2.rs2
-rw-r--r--src/test/parse-fail/issue-20711.rs2
-rw-r--r--src/test/parse-fail/issue-21153.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-static-fn.rs2
-rw-r--r--src/test/parse-fail/trait-pub-assoc-const.rs16
-rw-r--r--src/test/parse-fail/trait-pub-assoc-ty.rs3
-rw-r--r--src/test/parse-fail/trait-pub-method.rs3
-rw-r--r--src/test/run-pass/associated-const-inherent-impl.rs19
-rw-r--r--src/test/run-pass/associated-const-overwrite-default.rs23
-rw-r--r--src/test/run-pass/associated-const-public-impl.rs26
-rw-r--r--src/test/run-pass/associated-const-self-type.rs23
-rw-r--r--src/test/run-pass/associated-const-ufcs-infer-trait.rs23
-rw-r--r--src/test/run-pass/associated-const-use-default.rs21
-rw-r--r--src/test/run-pass/associated-const.rs23
43 files changed, 1387 insertions, 294 deletions
diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y
index 6c3fd186cd4..27e15bc2f0e 100644
--- a/src/grammar/parser-lalr.y
+++ b/src/grammar/parser-lalr.y
@@ -505,10 +505,20 @@ trait_items
 ;
 
 trait_item
-: trait_type
+: trait_const
+| trait_type
 | trait_method
 ;
 
+trait_const
+: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
+;
+
+maybe_const_default
+: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
+| %empty   { $$ = mk_none(); }
+;
+
 trait_type
 : maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
 ;
@@ -611,7 +621,16 @@ impl_items
 impl_item
 : impl_method
 | item_macro
-| trait_type
+| impl_const
+| impl_type
+;
+
+impl_const
+: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
+;
+
+impl_type
+: attrs_and_vis TYPE ident generic_params '=' ty_sum ';'  { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
 ;
 
 item_fn
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index d528e38d341..93056d949db 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -175,6 +175,13 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
     decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
 }
 
+pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
+                                   -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+    let cstore = &tcx.sess.cstore;
+    let cdata = cstore.get_crate_data(def.krate);
+    decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
+}
+
 pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
                           -> Option<ast::Name> {
     let cdata = cstore.get_crate_data(def.krate);
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 8e3f77f949b..00a7fe68f2f 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -305,7 +305,25 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
     -> DefLike {
     let fam = item_family(item);
     match fam {
-        Constant  => DlDef(def::DefConst(did)),
+        Constant  => {
+            // Check whether we have an associated const item.
+            if item_sort(item) == Some('C') {
+                // Check whether the associated const is from a trait or impl.
+                // See the comment for methods below.
+                let provenance = if reader::maybe_get_doc(
+                      item, tag_item_trait_parent_sort).is_some() {
+                    def::FromTrait(item_reqd_and_translated_parent_item(cnum,
+                                                                        item))
+                } else {
+                    def::FromImpl(item_reqd_and_translated_parent_item(cnum,
+                                                                       item))
+                };
+                DlDef(def::DefAssociatedConst(did, provenance))
+            } else {
+                // Regular const item.
+                DlDef(def::DefConst(did))
+            }
+        }
         ImmStatic => DlDef(def::DefStatic(did, false)),
         MutStatic => DlDef(def::DefStatic(did, true)),
         Struct    => DlDef(def::DefStruct(did)),
@@ -826,6 +844,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
                         tag_item_impl_item, |doc| {
         let def_id = item_def_id(doc, cdata);
         match item_sort(doc) {
+            Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
             Some('r') | Some('p') => {
                 impl_items.push(ty::MethodTraitItemId(def_id))
             }
@@ -877,6 +896,18 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
     let vis = item_visibility(method_doc);
 
     match item_sort(method_doc) {
+        Some('C') => {
+            let ty = doc_type(method_doc, tcx, cdata);
+            let default = get_provided_source(method_doc, cdata);
+            ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
+                name: name,
+                ty: ty,
+                vis: vis,
+                def_id: def_id,
+                container: container,
+                default: default,
+            }))
+        }
         Some('r') | Some('p') => {
             let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
             let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
@@ -914,6 +945,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
     reader::tagged_docs(item, tag_item_trait_item, |mth| {
         let def_id = item_def_id(mth, cdata);
         match item_sort(mth) {
+            Some('C') => result.push(ty::ConstTraitItemId(def_id)),
             Some('r') | Some('p') => {
                 result.push(ty::MethodTraitItemId(def_id));
             }
@@ -961,6 +993,34 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
     return result;
 }
 
+pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
+                                   cdata: Cmd,
+                                   id: ast::NodeId,
+                                   tcx: &ty::ctxt<'tcx>)
+                                   -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+    let data = cdata.data();
+    let item = lookup_item(id, data);
+    let mut result = Vec::new();
+
+    reader::tagged_docs(item, tag_item_trait_item, |ac_id| {
+        let did = item_def_id(ac_id, cdata);
+        let ac_doc = lookup_item(did.node, data);
+
+        if item_sort(ac_doc) == Some('C') {
+            let trait_item = get_impl_or_trait_item(intr.clone(),
+                                                    cdata,
+                                                    did.node,
+                                                    tcx);
+            if let ty::ConstTraitItem(ref ac) = trait_item {
+                result.push((*ac).clone())
+            }
+        }
+        true
+    });
+
+    return result;
+}
+
 pub fn get_type_name_if_impl(cdata: Cmd,
                              node_id: ast::NodeId) -> Option<ast::Name> {
     let item = lookup_item(node_id, cdata.data());
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 5f31e24a063..bcbb350fc34 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -799,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     encode_provided_source(rbml_w, method_ty.provided_source);
 }
 
+fn encode_info_for_associated_const(ecx: &EncodeContext,
+                                    rbml_w: &mut Encoder,
+                                    associated_const: &ty::AssociatedConst,
+                                    impl_path: PathElems,
+                                    parent_id: NodeId,
+                                    impl_item_opt: Option<&ast::ImplItem>) {
+    debug!("encode_info_for_associated_const({:?},{:?})",
+           associated_const.def_id,
+           token::get_name(associated_const.name));
+
+    rbml_w.start_tag(tag_items_data_item);
+
+    encode_def_id(rbml_w, associated_const.def_id);
+    encode_name(rbml_w, associated_const.name);
+    encode_visibility(rbml_w, associated_const.vis);
+    encode_family(rbml_w, 'C');
+    encode_provided_source(rbml_w, associated_const.default);
+
+    encode_parent_item(rbml_w, local_def(parent_id));
+    encode_item_sort(rbml_w, 'C');
+
+    encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
+
+    let stab = stability::lookup(ecx.tcx, associated_const.def_id);
+    encode_stability(rbml_w, stab);
+
+    let elem = ast_map::PathName(associated_const.name);
+    encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+
+    if let Some(ii) = impl_item_opt {
+        encode_attributes(rbml_w, &ii.attrs);
+        encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
+    }
+
+    rbml_w.end_tag();
+}
+
 fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                     rbml_w: &mut Encoder,
                                     m: &ty::Method<'tcx>,
@@ -1192,7 +1229,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
         for &item_def_id in items {
             rbml_w.start_tag(tag_item_impl_item);
             match item_def_id {
-                ty::ConstTraitItemId(_) => {}
+                ty::ConstTraitItemId(item_def_id) => {
+                    encode_def_id(rbml_w, item_def_id);
+                    encode_item_sort(rbml_w, 'C');
+                }
                 ty::MethodTraitItemId(item_def_id) => {
                     encode_def_id(rbml_w, item_def_id);
                     encode_item_sort(rbml_w, 'r');
@@ -1230,7 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
             });
 
             match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
-                ty::ConstTraitItem(_) => {}
+                ty::ConstTraitItem(ref associated_const) => {
+                    encode_info_for_associated_const(ecx,
+                                                     rbml_w,
+                                                     &*associated_const,
+                                                     path.clone(),
+                                                     item.id,
+                                                     ast_item)
+                }
                 ty::MethodTraitItem(ref method_type) => {
                     encode_info_for_method(ecx,
                                            rbml_w,
@@ -1275,7 +1322,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
         for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
             rbml_w.start_tag(tag_item_trait_item);
             match method_def_id {
-                ty::ConstTraitItemId(_) => {}
+                ty::ConstTraitItemId(const_def_id) => {
+                    encode_def_id(rbml_w, const_def_id);
+                    encode_item_sort(rbml_w, 'C');
+                }
                 ty::MethodTraitItemId(method_def_id) => {
                     encode_def_id(rbml_w, method_def_id);
                     encode_item_sort(rbml_w, 'r');
@@ -1321,7 +1371,23 @@ fn encode_info_for_item(ecx: &EncodeContext,
                 ty::impl_or_trait_item(tcx, item_def_id.def_id());
             let is_nonstatic_method;
             match trait_item_type {
-                ty::ConstTraitItem(_) => {
+                ty::ConstTraitItem(associated_const) => {
+                    encode_name(rbml_w, associated_const.name);
+                    encode_def_id(rbml_w, associated_const.def_id);
+                    encode_visibility(rbml_w, associated_const.vis);
+
+                    encode_provided_source(rbml_w, associated_const.default);
+
+                    let elem = ast_map::PathName(associated_const.name);
+                    encode_path(rbml_w,
+                                path.clone().chain(Some(elem).into_iter()));
+
+                    encode_item_sort(rbml_w, 'C');
+                    encode_family(rbml_w, 'C');
+
+                    encode_bounds_and_type_for_item(rbml_w, ecx,
+                                                    associated_const.def_id.local_id());
+
                     is_nonstatic_method = false;
                 }
                 ty::MethodTraitItem(method_ty) => {
@@ -1368,7 +1434,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
             let trait_item = &*ms[i];
             encode_attributes(rbml_w, &trait_item.attrs);
             match trait_item.node {
-                ast::ConstTraitItem(_, _) => {}
+                ast::ConstTraitItem(_, _) => {
+                    encode_inlined_item(ecx, rbml_w,
+                                        IITraitItemRef(def_id, trait_item));
+                }
                 ast::MethodTraitItem(ref sig, ref body) => {
                     // If this is a static method, we've already
                     // encoded this.
@@ -1388,9 +1457,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
                     encode_method_argument_names(rbml_w, &sig.decl);
                 }
 
-                ast::TypeTraitItem(..) => {
-                    encode_item_sort(rbml_w, 't');
-                }
+                ast::TypeTraitItem(..) => {}
             }
 
             rbml_w.end_tag();
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index ee9d1e01553..80326229618 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -223,6 +223,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         }
     }
 
+    fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
+        match t.node {
+            ast::ConstTraitItem(_, ref default) => {
+                if let Some(ref expr) = *default {
+                    self.global_expr(Mode::Const, &*expr);
+                } else {
+                    visit::walk_trait_item(self, t);
+                }
+            }
+            _ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
+        }
+    }
+
+    fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
+        match i.node {
+            ast::ConstImplItem(_, ref expr) => {
+                self.global_expr(Mode::Const, &*expr);
+            }
+            _ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
+        }
+    }
+
     fn visit_fn(&mut self,
                 fk: visit::FnKind<'v>,
                 fd: &'v ast::FnDecl,
@@ -468,13 +490,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                         Mode::Var => v.add_qualif(NOT_CONST)
                     }
                 }
-                Some(def::DefConst(did)) => {
-                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
+                Some(def::DefConst(did)) |
+                Some(def::DefAssociatedConst(did, _)) => {
+                    if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
+                                                                       Some(e.id)) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
                     } else {
-                        v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
-                                                     to an ItemConst");
+                        v.tcx.sess.span_bug(e.span,
+                                            "DefConst or DefAssociatedConst \
+                                             doesn't point to a constant");
                     }
                 }
                 def => {
diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs
index 912854a6d7d..13be6d0cb7d 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc/middle/check_match.rs
@@ -442,7 +442,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
             ast::PatIdent(..) | ast::PatEnum(..) => {
                 let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
                 match def {
-                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
+                    Some(DefAssociatedConst(did, _)) |
+                    Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
                         Some(const_expr) => {
                             const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
 
@@ -746,7 +747,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
     match pat.node {
         ast::PatIdent(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefStruct(_)) => vec!(Single),
@@ -755,7 +756,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             },
         ast::PatEnum(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => vec!(Variant(id)),
@@ -763,7 +764,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             },
         ast::PatStruct(..) =>
             match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat.span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => vec!(Variant(id)),
@@ -861,7 +862,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         ast::PatIdent(_, _, _) => {
             let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
             match opt_def {
-                Some(DefConst(..)) =>
+                Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
@@ -876,7 +877,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         ast::PatEnum(_, ref args) => {
             let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             match def {
-                DefConst(..) =>
+                DefConst(..) | DefAssociatedConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 DefVariant(_, id, _) if *constructor != Variant(id) => None,
@@ -894,7 +895,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
             // Is this a struct or an enum variant?
             let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             let class_id = match def {
-                DefConst(..) =>
+                DefConst(..) | DefAssociatedConst(..) =>
                     cx.tcx.sess.span_bug(pat_span, "const pattern should've \
                                                     been rewritten"),
                 DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs
index b97978fc03f..a521c4531c9 100644
--- a/src/librustc/middle/check_static_recursion.rs
+++ b/src/librustc/middle/check_static_recursion.rs
@@ -12,10 +12,11 @@
 // recursively.
 
 use session::Session;
-use middle::def::{DefStatic, DefConst, DefMap};
+use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
 
 use syntax::ast;
 use syntax::{ast_util, ast_map};
+use syntax::codemap::Span;
 use syntax::visit::Visitor;
 use syntax::visit;
 
@@ -26,8 +27,43 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
 }
 
 impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
-    fn visit_item(&mut self, i: &ast::Item) {
-        check_item(self, i);
+    fn visit_item(&mut self, it: &ast::Item) {
+        match it.node {
+            ast::ItemStatic(_, _, ref expr) |
+            ast::ItemConst(_, ref expr) => {
+                let mut recursion_visitor =
+                    CheckItemRecursionVisitor::new(self, &it.span);
+                recursion_visitor.visit_item(it);
+                visit::walk_expr(self, &*expr)
+            },
+            _ => visit::walk_item(self, it)
+        }
+    }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(_, ref default) => {
+                if let Some(ref expr) = *default {
+                    let mut recursion_visitor =
+                        CheckItemRecursionVisitor::new(self, &ti.span);
+                    recursion_visitor.visit_trait_item(ti);
+                    visit::walk_expr(self, &*expr)
+                }
+            }
+            _ => visit::walk_trait_item(self, ti)
+        }
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(_, ref expr) => {
+                let mut recursion_visitor =
+                    CheckItemRecursionVisitor::new(self, &ii.span);
+                recursion_visitor.visit_impl_item(ii);
+                visit::walk_expr(self, &*expr)
+            }
+            _ => visit::walk_impl_item(self, ii)
+        }
     }
 }
 
@@ -44,51 +80,48 @@ pub fn check_crate<'ast>(sess: &Session,
     sess.abort_if_errors();
 }
 
-fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
-    match it.node {
-        ast::ItemStatic(_, _, ref ex) |
-        ast::ItemConst(_, ref ex) => {
-            check_item_recursion(v.sess, v.ast_map, v.def_map, it);
-            visit::walk_expr(v, &**ex)
-        },
-        _ => visit::walk_item(v, it)
-    }
-}
-
 struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
-    root_it: &'a ast::Item,
+    root_span: &'a Span,
     sess: &'a Session,
     ast_map: &'a ast_map::Map<'ast>,
     def_map: &'a DefMap,
     idstack: Vec<ast::NodeId>
 }
 
-// Make sure a const item doesn't recursively refer to itself
-// FIXME: Should use the dependency graph when it's available (#1356)
-pub fn check_item_recursion<'a>(sess: &'a Session,
-                                ast_map: &'a ast_map::Map,
-                                def_map: &'a DefMap,
-                                it: &'a ast::Item) {
-
-    let mut visitor = CheckItemRecursionVisitor {
-        root_it: it,
-        sess: sess,
-        ast_map: ast_map,
-        def_map: def_map,
-        idstack: Vec::new()
-    };
-    visitor.visit_item(it);
+impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
+    fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span)
+           -> CheckItemRecursionVisitor<'a, 'ast> {
+        CheckItemRecursionVisitor {
+            root_span: span,
+            sess: v.sess,
+            ast_map: v.ast_map,
+            def_map: v.def_map,
+            idstack: Vec::new()
+        }
+    }
+    fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
+          where F: Fn(&mut Self) {
+        if self.idstack.iter().any(|x| x == &(id)) {
+            span_err!(self.sess, *self.root_span, E0265, "recursive constant");
+            return;
+        }
+        self.idstack.push(id);
+        f(self);
+        self.idstack.pop();
+    }
 }
 
 impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
     fn visit_item(&mut self, it: &ast::Item) {
-        if self.idstack.iter().any(|x| x == &(it.id)) {
-            span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
-            return;
-        }
-        self.idstack.push(it.id);
-        visit::walk_item(self, it);
-        self.idstack.pop();
+        self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
+    }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
     }
 
     fn visit_expr(&mut self, e: &ast::Expr) {
@@ -96,11 +129,16 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
             ast::ExprPath(..) => {
                 match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
                     Some(DefStatic(def_id, _)) |
+                    Some(DefAssociatedConst(def_id, _)) |
                     Some(DefConst(def_id)) if
                             ast_util::is_local(def_id) => {
                         match self.ast_map.get(def_id.node) {
                           ast_map::NodeItem(item) =>
                             self.visit_item(item),
+                          ast_map::NodeTraitItem(item) =>
+                            self.visit_trait_item(item),
+                          ast_map::NodeImplItem(item) =>
+                            self.visit_impl_item(item),
                           ast_map::NodeForeignItem(_) => {},
                           _ => {
                             span_err!(self.sess, e.span, E0266,
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 2c6ffb3281f..b5a173a569f 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -16,11 +16,12 @@ pub use self::const_val::*;
 use self::ErrKind::*;
 
 use metadata::csearch;
-use middle::{astencode, def};
+use middle::{astencode, def, infer, subst, traits};
 use middle::pat_util::def_to_path;
 use middle::ty::{self, Ty};
 use middle::astconv_util::ast_ty_to_prim_ty;
 use util::num::ToPrimitive;
+use util::ppaux::Repr;
 
 use syntax::ast::{self, Expr};
 use syntax::codemap::Span;
@@ -39,8 +40,9 @@ use std::rc::Rc;
 fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
     let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
     match opt_def {
-        Some(def::DefConst(def_id)) => {
-            lookup_const_by_id(tcx, def_id)
+        Some(def::DefConst(def_id)) |
+        Some(def::DefAssociatedConst(def_id, _)) => {
+            lookup_const_by_id(tcx, def_id, Some(e.id))
         }
         Some(def::DefVariant(enum_def, variant_def, _)) => {
             lookup_variant_by_id(tcx, enum_def, variant_def)
@@ -101,14 +103,36 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
     }
 }
 
-pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
-                          -> Option<&'a Expr> {
+pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+                                        def_id: ast::DefId,
+                                        maybe_ref_id: Option<ast::NodeId>)
+                                        -> Option<&'tcx Expr> {
     if ast_util::is_local(def_id) {
         match tcx.map.find(def_id.node) {
             None => None,
             Some(ast_map::NodeItem(it)) => match it.node {
                 ast::ItemConst(_, ref const_expr) => {
-                    Some(&**const_expr)
+                    Some(&*const_expr)
+                }
+                _ => None
+            },
+            Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+                ast::ConstTraitItem(_, ref default) => {
+                    match maybe_ref_id {
+                        Some(ref_id) => {
+                            let trait_id = ty::trait_of_item(tcx, def_id)
+                                              .unwrap();
+                            resolve_trait_associated_const(tcx, ti, trait_id,
+                                                           ref_id)
+                        }
+                        None => default.as_ref().map(|expr| &**expr),
+                    }
+                }
+                _ => None
+            },
+            Some(ast_map::NodeImplItem(ii)) => match ii.node {
+                ast::ConstImplItem(_, ref expr) => {
+                    Some(&*expr)
                 }
                 _ => None
             },
@@ -122,16 +146,42 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
             }
             None => {}
         }
+        let mut used_ref_id = false;
         let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
             Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
             csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node {
                 ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
                 _ => None
             },
+            csearch::FoundAst::Found(&ast::IITraitItem(_, ref ti)) => match ti.node {
+                ast::ConstTraitItem(_, ref default) => {
+                    used_ref_id = true;
+                    match maybe_ref_id {
+                        Some(ref_id) => {
+                            let trait_id = ty::trait_of_item(tcx, def_id)
+                                              .unwrap();
+                            resolve_trait_associated_const(tcx, ti, trait_id,
+                                                           ref_id).map(|e| e.id)
+                        }
+                        None => default.as_ref().map(|expr| expr.id),
+                    }
+                }
+                _ => None
+            },
+            csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node {
+                ast::ConstImplItem(_, ref expr) => Some(expr.id),
+                _ => None
+            },
             _ => None
         };
-        tcx.extern_const_statics.borrow_mut().insert(def_id,
-                                                     expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+        // If we used the reference expression, particularly to choose an impl
+        // of a trait-associated const, don't cache that, because the next
+        // lookup with the same def_id may yield a different result.
+        if used_ref_id {
+            tcx.extern_const_statics
+               .borrow_mut().insert(def_id,
+                                    expr_id.unwrap_or(ast::DUMMY_NODE_ID));
+        }
         expr_id.map(|id| tcx.map.expect_expr(id))
     }
 }
@@ -755,7 +805,35 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
                           _ => (None, None)
                       }
                   } else {
-                      (lookup_const_by_id(tcx, def_id), None)
+                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
+                  }
+              }
+              Some(def::DefAssociatedConst(def_id, provenance)) => {
+                  if ast_util::is_local(def_id) {
+                      match provenance {
+                          def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
+                              Some(ast_map::NodeTraitItem(ti)) => match ti.node {
+                                  ast::ConstTraitItem(ref ty, _) => {
+                                      (resolve_trait_associated_const(tcx, ti,
+                                                                      trait_id, e.id),
+                                       Some(&**ty))
+                                  }
+                                  _ => (None, None)
+                              },
+                              _ => (None, None)
+                          },
+                          def::FromImpl(_) => match tcx.map.find(def_id.node) {
+                              Some(ast_map::NodeImplItem(ii)) => match ii.node {
+                                  ast::ConstImplItem(ref ty, ref expr) => {
+                                      (Some(&**expr), Some(&**ty))
+                                  }
+                                  _ => (None, None)
+                              },
+                              _ => (None, None)
+                          },
+                      }
+                  } else {
+                      (lookup_const_by_id(tcx, def_id, Some(e.id)), None)
                   }
               }
               Some(def::DefVariant(enum_def, variant_def, _)) => {
@@ -833,6 +911,71 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
     Ok(result)
 }
 
+fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
+                                                ti: &'tcx ast::TraitItem,
+                                                trait_id: ast::DefId,
+                                                ref_id: ast::NodeId)
+                                                -> Option<&'tcx Expr>
+{
+    let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
+    let subst::SeparateVecsPerParamSpace {
+        types: rcvr_type,
+        selfs: rcvr_self,
+        fns: _,
+    } = rcvr_substs.types.split();
+    let trait_substs =
+        subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
+                                                           rcvr_self,
+                                                           Vec::new()));
+    let trait_substs = tcx.mk_substs(trait_substs);
+    debug!("resolve_trait_associated_const: trait_substs={}",
+           trait_substs.repr(tcx));
+    let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
+                                                      substs: trait_substs }));
+
+    ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
+    let infcx = infer::new_infer_ctxt(tcx);
+
+    let param_env = ty::empty_parameter_environment(tcx);
+    let mut selcx = traits::SelectionContext::new(&infcx, &param_env);
+    let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
+                                             trait_ref.to_poly_trait_predicate());
+    let selection = match selcx.select(&obligation) {
+        Ok(Some(vtable)) => vtable,
+        // Still ambiguous, so give up and let the caller decide whether this
+        // expression is really needed yet. Some associated constant values
+        // can't be evaluated until monomorphization is done in trans.
+        Ok(None) => {
+            return None
+        }
+        Err(e) => {
+            tcx.sess.span_bug(ti.span,
+                              &format!("Encountered error `{}` when trying \
+                                        to select an implementation for \
+                                        constant trait item reference.",
+                                       e.repr(tcx)))
+        }
+    };
+
+    match selection {
+        traits::VtableImpl(ref impl_data) => {
+            match ty::associated_consts(tcx, impl_data.impl_def_id)
+                     .iter().find(|ic| ic.name == ti.ident.name) {
+                Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+                None => match ti.node {
+                    ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
+                    _ => None,
+                },
+            }
+        }
+        _ => {
+            tcx.sess.span_bug(
+                ti.span,
+                &format!("resolve_trait_associated_const: unexpected vtable type"))
+        }
+    }
+}
+
 fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
     macro_rules! convert_val {
         ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 3f5f40ec0b5..1b5e31f61d8 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -78,7 +78,7 @@ use std::vec::IntoIter;
 use collections::enum_set::{EnumSet, CLike};
 use std::collections::{HashMap, HashSet};
 use syntax::abi;
-use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
+use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
 use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
 use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
 use syntax::ast_util::{self, is_local, lit_is_str, local_def};
@@ -5125,6 +5125,53 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
     }
 }
 
+pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
+                               -> Vec<Rc<AssociatedConst<'tcx>>> {
+    if is_local(id) {
+        match cx.map.expect_item(id.node).node {
+            ItemTrait(_, _, _, ref tis) => {
+                tis.iter().filter_map(|ti| {
+                    if let ast::ConstTraitItem(_, _) = ti.node {
+                        match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
+                            ConstTraitItem(ac) => Some(ac),
+                            _ => {
+                                cx.sess.bug("associated_consts(): \
+                                             non-const item found from \
+                                             looking up a constant?!")
+                            }
+                        }
+                    } else {
+                        None
+                    }
+                }).collect()
+            }
+            ItemImpl(_, _, _, _, _, ref iis) => {
+                iis.iter().filter_map(|ii| {
+                    if let ast::ConstImplItem(_, _) = ii.node {
+                        match impl_or_trait_item(cx, ast_util::local_def(ii.id)) {
+                            ConstTraitItem(ac) => Some(ac),
+                            _ => {
+                                cx.sess.bug("associated_consts(): \
+                                             non-const item found from \
+                                             looking up a constant?!")
+                            }
+                        }
+                    } else {
+                        None
+                    }
+                }).collect()
+            }
+            _ => {
+                cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \
+                                      or impl", id))
+            }
+        }
+    } else {
+        let acs = csearch::get_associated_consts(cx, id);
+        acs.iter().map(|ac| (*ac).clone()).collect()
+    }
+}
+
 /// Helper for looking things up in the various maps that are populated during
 /// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc).  All of
 /// these share the pattern that if the id is local, it should have been loaded
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 502321d0759..19cdc194153 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -62,6 +62,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
     fn visit_item(&mut self, item: &ast::Item) {
         borrowck_item(self, item);
     }
+
+    fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
+        if let ast::ConstTraitItem(_, Some(ref expr)) = ti.node {
+            gather_loans::gather_loans_in_static_initializer(self, &*expr);
+        }
+        visit::walk_trait_item(self, ti);
+    }
+
+    fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
+        if let ast::ConstImplItem(_, ref expr) = ii.node {
+            gather_loans::gather_loans_in_static_initializer(self, &*expr);
+        }
+        visit::walk_impl_item(self, ii);
+    }
 }
 
 pub fn check_crate(tcx: &ty::ctxt) {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 00c3450ebb9..b8032bda8d0 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -35,6 +35,7 @@ use syntax::codemap;
 use syntax::fold::{self, Folder};
 use syntax::print::{pp, pprust};
 use syntax::ptr::P;
+use syntax::util::small_vector::SmallVector;
 
 use graphviz as dot;
 
@@ -475,6 +476,29 @@ impl fold::Folder for ReplaceBodyWithLoop {
         }
     }
 
+    fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
+        match i.node {
+            ast::ConstTraitItem(..) => {
+                self.within_static_or_const = true;
+                let ret = fold::noop_fold_trait_item(i, self);
+                self.within_static_or_const = false;
+                return ret;
+            }
+            _ => fold::noop_fold_trait_item(i, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
+        match i.node {
+            ast::ConstImplItem(..) => {
+                self.within_static_or_const = true;
+                let ret = fold::noop_fold_impl_item(i, self);
+                self.within_static_or_const = false;
+                return ret;
+            }
+            _ => fold::noop_fold_impl_item(i, self),
+        }
+    }
 
     fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
         fn expr_to_block(rules: ast::BlockCheckMode,
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f4761f95505..902e9ffca1f 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1068,9 +1068,30 @@ impl LintPass for NonUpperCaseGlobals {
         }
     }
 
+    fn check_trait_item(&mut self, cx: &Context, ti: &ast::TraitItem) {
+        match ti.node {
+            ast::ConstTraitItem(..) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+                                                      ti.ident, ti.span);
+            }
+            _ => {}
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &Context, ii: &ast::ImplItem) {
+        match ii.node {
+            ast::ConstImplItem(..) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+                                                      ii.ident, ii.span);
+            }
+            _ => {}
+        }
+    }
+
     fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
         // Lint for constants that look like binding identifiers (#7526)
         match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
+            (&ast::PatIdent(_, ref path1, _), Some(def::DefAssociatedConst(..))) |
             (&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
                                                       path1.node, p.span);
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 832a33e3fe0..128e29ee76e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -119,6 +119,15 @@ impl<'v> Visitor<'v> for ParentVisitor {
         visit::walk_fn(self, a, b, c, d);
     }
 
+    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
+        // visit_fn handles methods, but associated consts have to be handled
+        // here.
+        if !self.parents.contains_key(&ii.id) {
+            self.parents.insert(ii.id, self.curparent);
+        }
+        visit::walk_impl_item(self, ii);
+    }
+
     fn visit_struct_def(&mut self, s: &ast::StructDef, _: ast::Ident,
                         _: &'v ast::Generics, n: ast::NodeId) {
         // Struct constructors are parented to their struct definitions because
@@ -272,7 +281,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                 if public_ty || public_trait {
                     for impl_item in impl_items {
                         match impl_item.node {
-                            ast::ConstImplItem(_, _) => {}
+                            ast::ConstImplItem(..) => {
+                                if (public_ty && impl_item.vis == ast::Public)
+                                    || tr.is_some() {
+                                    self.exported_items.insert(impl_item.id);
+                                }
+                            }
                             ast::MethodImplItem(ref sig, _) => {
                                 let meth_public = match sig.explicit_self.node {
                                     ast::SelfStatic => public_ty,
@@ -400,7 +414,33 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             debug!("privacy - is {:?} a public method", did);
 
             return match self.tcx.impl_or_trait_items.borrow().get(&did) {
-                Some(&ty::ConstTraitItem(_)) => ExternallyDenied,
+                Some(&ty::ConstTraitItem(ref ac)) => {
+                    debug!("privacy - it's a const: {:?}", *ac);
+                    match ac.container {
+                        ty::TraitContainer(id) => {
+                            debug!("privacy - recursing on trait {:?}", id);
+                            self.def_privacy(id)
+                        }
+                        ty::ImplContainer(id) => {
+                            match ty::impl_trait_ref(self.tcx, id) {
+                                Some(t) => {
+                                    debug!("privacy - impl of trait {:?}", id);
+                                    self.def_privacy(t.def_id)
+                                }
+                                None => {
+                                    debug!("privacy - found inherent \
+                                            associated constant {:?}",
+                                            ac.vis);
+                                    if ac.vis == ast::Public {
+                                        Allowable
+                                    } else {
+                                        ExternallyDenied
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 Some(&ty::MethodTraitItem(ref meth)) => {
                     debug!("privacy - well at least it's a method: {:?}",
                            *meth);
@@ -794,6 +834,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             def::DefFn(..) => ck("function"),
             def::DefStatic(..) => ck("static"),
             def::DefConst(..) => ck("const"),
+            def::DefAssociatedConst(..) => ck("associated const"),
             def::DefVariant(..) => ck("variant"),
             def::DefTy(_, false) => ck("type"),
             def::DefTy(_, true) => ck("enum"),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index f43d951aaaa..41a6f4adfe0 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1831,22 +1831,36 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             //
                             // FIXME #4951: Do we need a node ID here?
 
-                            let type_parameters = match trait_item.node {
-                                ast::ConstTraitItem(..) => NoTypeParameters,
+                            match trait_item.node {
+                                ast::ConstTraitItem(_, ref default) => {
+                                    // Only impose the restrictions of
+                                    // ConstRibKind if there's an actual constant
+                                    // expression in a provided default.
+                                    if default.is_some() {
+                                        this.with_constant_rib(|this| {
+                                            visit::walk_trait_item(this, trait_item)
+                                        });
+                                    } else {
+                                        visit::walk_trait_item(this, trait_item)
+                                    }
+                                }
                                 ast::MethodTraitItem(ref sig, _) => {
-                                    HasTypeParameters(&sig.generics,
-                                                      FnSpace,
-                                                      MethodRibKind)
+                                    let type_parameters =
+                                        HasTypeParameters(&sig.generics,
+                                                          FnSpace,
+                                                          MethodRibKind);
+                                    this.with_type_parameter_rib(type_parameters, |this| {
+                                        visit::walk_trait_item(this, trait_item)
+                                    });
                                 }
                                 ast::TypeTraitItem(..) => {
                                     this.check_if_primitive_type_name(trait_item.ident.name,
                                                                       trait_item.span);
-                                    NoTypeParameters
+                                    this.with_type_parameter_rib(NoTypeParameters, |this| {
+                                        visit::walk_trait_item(this, trait_item)
+                                    });
                                 }
                             };
-                            this.with_type_parameter_rib(type_parameters, |this| {
-                                visit::walk_trait_item(this, trait_item)
-                            });
                         }
                     });
                 });
@@ -2096,7 +2110,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     this.with_current_self_type(self_type, |this| {
                         for impl_item in impl_items {
                             match impl_item.node {
-                                ConstImplItem(_, _) => {}
+                                ConstImplItem(..) => {
+                                    // If this is a trait impl, ensure the method
+                                    // exists in trait
+                                    this.check_trait_item(impl_item.ident.name,
+                                                          impl_item.span);
+                                    this.with_constant_rib(|this| {
+                                        visit::walk_impl_item(this, impl_item);
+                                    });
+                                }
                                 MethodImplItem(ref sig, _) => {
                                     // If this is a trait impl, ensure the method
                                     // exists in trait
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 237270da562..dc14ef3696f 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -539,25 +539,27 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
     }
 
     fn process_const(&mut self,
-                      item: &ast::Item,
-                      typ: &ast::Ty,
-                      expr: &ast::Expr)
+                     id: ast::NodeId,
+                     ident: &ast::Ident,
+                     span: Span,
+                     typ: &ast::Ty,
+                     expr: &ast::Expr)
     {
-        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+        let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
 
-        let sub_span = self.span.sub_span_after_keyword(item.span,
+        let sub_span = self.span.sub_span_after_keyword(span,
                                                         keywords::Const);
-        self.fmt.static_str(item.span,
+        self.fmt.static_str(span,
                             sub_span,
-                            item.id,
-                            &get_ident(item.ident),
+                            id,
+                            &get_ident((*ident).clone()),
                             &qualname[..],
                             "",
                             &ty_to_string(&*typ),
                             self.cur_scope);
 
         // walk type and init value
-        self.visit_ty(&*typ);
+        self.visit_ty(typ);
         self.visit_expr(expr);
     }
 
@@ -1188,7 +1190,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
             ast::ItemStatic(ref typ, mt, ref expr) =>
                 self.process_static(item, &**typ, mt, &**expr),
             ast::ItemConst(ref typ, ref expr) =>
-                self.process_const(item, &**typ, &**expr),
+                self.process_const(item.id, &item.ident, item.span, &*typ, &*expr),
             ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
             ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
             ast::ItemImpl(_, _,
@@ -1238,18 +1240,25 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
         match trait_item.node {
-            ast::ConstTraitItem(..) => {}
+            ast::ConstTraitItem(ref ty, Some(ref expr)) => {
+                self.process_const(trait_item.id, &trait_item.ident,
+                                   trait_item.span, &*ty, &*expr);
+            }
             ast::MethodTraitItem(ref sig, ref body) => {
                 self.process_method(sig, body.as_ref().map(|x| &**x),
                                     trait_item.id, trait_item.ident.name, trait_item.span);
             }
+            ast::ConstTraitItem(_, None) |
             ast::TypeTraitItem(..) => {}
         }
     }
 
     fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
         match impl_item.node {
-            ast::ConstImplItem(..) => {}
+            ast::ConstImplItem(ref ty, ref expr) => {
+                self.process_const(impl_item.id, &impl_item.ident,
+                                   impl_item.span, &*ty, &*expr);
+            }
             ast::MethodImplItem(ref sig, ref body) => {
                 self.process_method(sig, Some(body), impl_item.id,
                                     impl_item.ident.name, impl_item.span);
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 38136b03a21..9932899ed8f 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -173,13 +173,11 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                             "cross crate constant could not be inlined");
     }
 
-    let item = ccx.tcx().map.expect_item(def_id.node);
-    if let ast::ItemConst(_, ref expr) = item.node {
-        &**expr
-    } else {
-        ccx.sess().span_bug(ref_expr.span,
-                            &format!("get_const_expr given non-constant item {}",
-                                     item.repr(ccx.tcx())));
+    match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
+        Some(ref expr) => expr,
+        None => {
+            ccx.sess().span_bug(ref_expr.span, "constant item not found")
+        }
     }
 }
 
@@ -201,7 +199,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         ast::ExprPath(..) => {
             let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
             match def {
-                def::DefConst(def_id) => {
+                def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
                     if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
                         return get_const_val(ccx, def_id, expr);
                     }
@@ -774,7 +772,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 def::DefFn(..) | def::DefMethod(..) => {
                     expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
                 }
-                def::DefConst(def_id) => {
+                def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
                     const_deref_ptr(cx, get_const_val(cx, def_id, e))
                 }
                 def::DefVariant(enum_did, variant_did, _) => {
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 532277d75b2..9f0a03878be 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -401,3 +401,85 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
         return true;
     }
 }
+
+pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                impl_c: &ty::AssociatedConst<'tcx>,
+                                impl_c_span: Span,
+                                trait_c: &ty::AssociatedConst<'tcx>,
+                                impl_trait_ref: &ty::TraitRef<'tcx>) {
+    debug!("compare_const_impl(impl_trait_ref={})",
+           impl_trait_ref.repr(tcx));
+
+    let infcx = infer::new_infer_ctxt(tcx);
+    let mut fulfillment_cx = traits::FulfillmentContext::new();
+
+    // The below is for the most part highly similar to the procedure
+    // for methods above. It is simpler in many respects, especially
+    // because we shouldn't really have to deal with lifetimes or
+    // predicates. In fact some of this should probably be put into
+    // shared functions because of DRY violations...
+    let trait_to_impl_substs = &impl_trait_ref.substs;
+
+    // Create a parameter environment that represents the implementation's
+    // method.
+    let impl_param_env =
+        ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
+
+    // Create mapping from impl to skolemized.
+    let impl_to_skol_substs = &impl_param_env.free_substs;
+
+    // Create mapping from trait to skolemized.
+    let trait_to_skol_substs =
+        trait_to_impl_substs
+        .subst(tcx, impl_to_skol_substs)
+        .with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
+                     impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
+    debug!("compare_const_impl: trait_to_skol_substs={}",
+           trait_to_skol_substs.repr(tcx));
+
+    // Compute skolemized form of impl and trait const tys.
+    let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
+    let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
+
+    let err = infcx.commit_if_ok(|_| {
+        let origin = infer::Misc(impl_c_span);
+
+        // There is no "body" here, so just pass dummy id.
+        let impl_ty =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_c_span,
+                                                 0,
+                                                 &impl_ty);
+        debug!("compare_const_impl: impl_ty={}",
+               impl_ty.repr(tcx));
+
+        let trait_ty =
+            assoc::normalize_associated_types_in(&infcx,
+                                                 &impl_param_env,
+                                                 &mut fulfillment_cx,
+                                                 impl_c_span,
+                                                 0,
+                                                 &trait_ty);
+        debug!("compare_const_impl: trait_ty={}",
+               trait_ty.repr(tcx));
+
+        infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
+    });
+
+    match err {
+        Ok(()) => { }
+        Err(terr) => {
+            debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
+                   impl_ty.repr(tcx),
+                   trait_ty.repr(tcx));
+            span_err!(tcx.sess, impl_c_span, E0326,
+                      "implemented const `{}` has an incompatible type for \
+                      trait: {}",
+                      token::get_name(trait_c.name),
+                      ty::type_err_to_str(tcx, &terr));
+            return;
+        }
+    }
+}
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 7eb15a14796..cf1323e71bd 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -109,10 +109,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         self.add_obligations(&pick, &all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
+        let method_ty = pick.item.as_opt_method().unwrap();
         let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
             sig: ty::Binder(method_sig),
-            unsafety: pick.method_ty.fty.unsafety,
-            abi: pick.method_ty.fty.abi.clone(),
+            unsafety: method_ty.fty.unsafety,
+            abi: method_ty.fty.abi.clone(),
         }));
         let callee = MethodCallee {
             origin: method_origin,
@@ -204,7 +205,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         "impl {:?} is not an inherent impl", impl_def_id);
                 let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
 
-                (impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
+                (impl_polytype.substs, MethodStatic(pick.item.def_id()))
             }
 
             probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
@@ -336,7 +337,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // If they were not explicitly supplied, just construct fresh
         // variables.
         let num_supplied_types = supplied_method_types.len();
-        let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
+        let num_method_types = pick.item.as_opt_method().unwrap()
+                                   .generics.types.len(subst::FnSpace);
         let method_types = {
             if num_supplied_types == 0 {
                 self.fcx.infcx().next_ty_vars(num_method_types)
@@ -360,7 +362,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         let method_regions =
             self.fcx.infcx().region_vars_for_defs(
                 self.span,
-                pick.method_ty.generics.regions.get_slice(subst::FnSpace));
+                pick.item.as_opt_method().unwrap()
+                    .generics.regions.get_slice(subst::FnSpace));
 
         (method_types, method_regions)
     }
@@ -397,7 +400,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // Instantiate the bounds on the method with the
         // type/early-bound-regions substitutions performed. There can
         // be no late-bound regions appearing here.
-        let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
+        let method_predicates = pick.item.as_opt_method().unwrap()
+                                    .predicates.instantiate(self.tcx(), &all_substs);
         let method_predicates = self.fcx.normalize_associated_types_in(self.span,
                                                                        &method_predicates);
 
@@ -410,7 +414,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // NB: Instantiate late-bound regions first so that
         // `instantiate_type_scheme` can normalize associated types that
         // may reference those regions.
-        let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
+        let method_sig = self.replace_late_bound_regions_with_fresh_var(
+            &pick.item.as_opt_method().unwrap().fty.sig);
         debug!("late-bound lifetimes from method instantiated, method_sig={}",
                method_sig.repr(self.tcx()));
 
@@ -616,7 +621,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
-        match pick.method_ty.container {
+        match pick.item.container() {
             ty::TraitContainer(trait_def_id) => {
                 callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
             }
@@ -625,7 +630,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 // potential calls to it will wind up in the other
                 // arm. But just to be sure, check that the method id
                 // does not appear in the list of destructors.
-                assert!(!self.tcx().destructors.borrow().contains(&pick.method_ty.def_id));
+                assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index f1a4dbf7cd5..c5d8e2758ba 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -58,7 +58,7 @@ pub enum CandidateSource {
     TraitSource(/* trait id */ ast::DefId),
 }
 
-type MethodIndex = usize; // just for doc purposes
+type ItemIndex = usize; // just for doc purposes
 
 /// Determines whether the type `self_ty` supports a method name `method_name` or not.
 pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -312,18 +312,25 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 {
     let mode = probe::Mode::Path;
     let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
-    let def_id = pick.method_ty.def_id;
+    let def_id = pick.item.def_id();
     let mut lp = LastMod(AllPublic);
     let provenance = match pick.kind {
         probe::InherentImplPick(impl_def_id) => {
-            if pick.method_ty.vis != ast::Public {
+            if pick.item.vis() != ast::Public {
                 lp = LastMod(DependsOn(def_id));
             }
             def::FromImpl(impl_def_id)
         }
-        _ => def::FromTrait(pick.method_ty.container.id())
+        _ => def::FromTrait(pick.item.container().id())
     };
-    Ok((def::DefMethod(def_id, provenance), lp))
+    let def_result = match pick.item {
+        ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
+        ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
+        ImplOrTraitItem::TypeTraitItem(..) => {
+            fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
+        }
+    };
+    Ok((def_result, lp))
 }
 
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 08e2f47c5a6..7ff1355184b 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use super::MethodError;
-use super::MethodIndex;
+use super::ItemIndex;
 use super::{CandidateSource,ImplSource,TraitSource};
 use super::suggest;
 
@@ -37,7 +37,7 @@ struct ProbeContext<'a, 'tcx:'a> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     span: Span,
     mode: Mode,
-    method_name: ast::Name,
+    item_name: ast::Name,
     steps: Rc<Vec<CandidateStep<'tcx>>>,
     opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
     inherent_candidates: Vec<Candidate<'tcx>>,
@@ -54,7 +54,7 @@ struct CandidateStep<'tcx> {
 
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
-    method_ty: Rc<ty::Method<'tcx>>,
+    item: ty::ImplOrTraitItem<'tcx>,
     kind: CandidateKind<'tcx>,
 }
 
@@ -62,14 +62,14 @@ enum CandidateKind<'tcx> {
     InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
     ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
     ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
-                           subst::Substs<'tcx>, MethodIndex),
-    ClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
-    WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
-    ProjectionCandidate(ast::DefId, MethodIndex),
+                           subst::Substs<'tcx>, ItemIndex),
+    ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
+    WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
+    ProjectionCandidate(ast::DefId, ItemIndex),
 }
 
 pub struct Pick<'tcx> {
-    pub method_ty: Rc<ty::Method<'tcx>>,
+    pub item: ty::ImplOrTraitItem<'tcx>,
     pub kind: PickKind<'tcx>,
 
     // Indicates that the source expression should be autoderef'd N times
@@ -94,20 +94,20 @@ pub struct Pick<'tcx> {
 pub enum PickKind<'tcx> {
     InherentImplPick(/* Impl */ ast::DefId),
     ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
-    ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex),
-    TraitPick(/* Trait */ ast::DefId, MethodIndex),
-    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
+    ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
+    TraitPick(/* Trait */ ast::DefId, ItemIndex),
+    WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
 }
 
 pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
 
-#[derive(PartialEq, Eq, Copy, Clone)]
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
 pub enum Mode {
     // An expression of the form `receiver.method_name(...)`.
     // Autoderefs are performed on `receiver`, lookup is done based on the
     // `self` argument  of the method, and static methods aren't considered.
     MethodCall,
-    // An expression of the form `Type::method` or `<T>::method`.
+    // An expression of the form `Type::item` or `<T>::item`.
     // No autoderefs are performed, lookup is done based on the type each
     // implementation is for, and static methods are included.
     Path
@@ -116,14 +116,14 @@ pub enum Mode {
 pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                        span: Span,
                        mode: Mode,
-                       method_name: ast::Name,
+                       item_name: ast::Name,
                        self_ty: Ty<'tcx>,
                        scope_expr_id: ast::NodeId)
                        -> PickResult<'tcx>
 {
-    debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
+    debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
            self_ty.repr(fcx.tcx()),
-           method_name,
+           item_name,
            scope_expr_id);
 
     // FIXME(#18741) -- right now, creating the steps involves evaluating the
@@ -171,7 +171,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         let mut probe_cx = ProbeContext::new(fcx,
                                              span,
                                              mode,
-                                             method_name,
+                                             item_name,
                                              steps,
                                              opt_simplified_steps);
         probe_cx.assemble_inherent_candidates();
@@ -221,7 +221,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     fn new(fcx: &'a FnCtxt<'a,'tcx>,
            span: Span,
            mode: Mode,
-           method_name: ast::Name,
+           item_name: ast::Name,
            steps: Vec<CandidateStep<'tcx>>,
            opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
            -> ProbeContext<'a,'tcx>
@@ -230,7 +230,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             fcx: fcx,
             span: span,
             mode: mode,
-            method_name: method_name,
+            item_name: item_name,
             inherent_candidates: Vec::new(),
             extension_candidates: Vec::new(),
             impl_dups: HashSet::new(),
@@ -387,12 +387,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
         debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
 
-        let method = match impl_method(self.tcx(), impl_def_id, self.method_name) {
+        let item = match impl_item(self.tcx(), impl_def_id, self.item_name) {
             Some(m) => m,
             None => { return; } // No method with correct name on this impl
         };
 
-        if !self.has_applicable_self(&*method) {
+        if !self.has_applicable_self(&item) {
             // No receiver declared. Not a candidate.
             return self.record_static_candidate(ImplSource(impl_def_id));
         }
@@ -402,11 +402,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
         // Determine the receiver type that the method itself expects.
         let xform_self_ty =
-            self.xform_self_ty(&method, impl_ty, &impl_substs);
+            self.xform_self_ty(&item, impl_ty, &impl_substs);
 
         self.inherent_candidates.push(Candidate {
             xform_self_ty: xform_self_ty,
-            method_ty: method,
+            item: item,
             kind: InherentImplCandidate(impl_def_id, impl_substs)
         });
     }
@@ -427,23 +427,23 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         // itself. Hence, a `&self` method will wind up with an
         // argument type like `&Trait`.
         let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
-        self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
+        self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
             let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
 
             let vtable_index =
                 traits::get_vtable_index_of_object_method(tcx,
                                                           trait_ref.clone(),
                                                           new_trait_ref.def_id,
-                                                          method_num);
+                                                          item_num);
 
-            let xform_self_ty = this.xform_self_ty(&m,
+            let xform_self_ty = this.xform_self_ty(&item,
                                                    new_trait_ref.self_ty(),
                                                    new_trait_ref.substs);
 
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: m,
-                kind: ObjectCandidate(new_trait_ref.def_id, method_num, vtable_index)
+                item: item,
+                kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
             });
         });
     }
@@ -476,27 +476,29 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             })
             .collect();
 
-        self.elaborate_bounds(&bounds, |this, poly_trait_ref, m, method_num| {
+        self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
             let trait_ref =
                 this.erase_late_bound_regions(&poly_trait_ref);
 
             let xform_self_ty =
-                this.xform_self_ty(&m,
+                this.xform_self_ty(&item,
                                    trait_ref.self_ty(),
                                    trait_ref.substs);
 
-            debug!("found match: trait_ref={} substs={} m={}",
-                   trait_ref.repr(this.tcx()),
-                   trait_ref.substs.repr(this.tcx()),
-                   m.repr(this.tcx()));
-            assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
-                       trait_ref.substs.types.get_slice(subst::TypeSpace).len());
-            assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
-                       trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
-            assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
-                       trait_ref.substs.types.get_slice(subst::SelfSpace).len());
-            assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
-                       trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+            if let Some(ref m) = item.as_opt_method() {
+                debug!("found match: trait_ref={} substs={} m={}",
+                       trait_ref.repr(this.tcx()),
+                       trait_ref.substs.repr(this.tcx()),
+                       m.repr(this.tcx()));
+                assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
+                assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.types.get_slice(subst::SelfSpace).len());
+                assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
+                           trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
+            }
 
             // Because this trait derives from a where-clause, it
             // should not contain any inference variables or other
@@ -507,8 +509,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
             this.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: m,
-                kind: WhereClauseCandidate(poly_trait_ref, method_num)
+                item: item,
+                kind: WhereClauseCandidate(poly_trait_ref, item_num)
             });
         });
     }
@@ -523,7 +525,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         F: for<'b> FnMut(
             &mut ProbeContext<'b, 'tcx>,
             ty::PolyTraitRef<'tcx>,
-            Rc<ty::Method<'tcx>>,
+            ty::ImplOrTraitItem<'tcx>,
             usize,
         ),
     {
@@ -531,17 +533,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
         let tcx = self.tcx();
         for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
-            let (pos, method) = match trait_method(tcx,
-                                                   bound_trait_ref.def_id(),
-                                                   self.method_name) {
+            let (pos, item) = match trait_item(tcx,
+                                               bound_trait_ref.def_id(),
+                                               self.item_name) {
                 Some(v) => v,
                 None => { continue; }
             };
 
-            if !self.has_applicable_self(&*method) {
+            if !self.has_applicable_self(&item) {
                 self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
             } else {
-                mk_cand(self, bound_trait_ref, method, pos);
+                mk_cand(self, bound_trait_ref, item, pos);
             }
         }
     }
@@ -584,37 +586,34 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             ty::trait_items(self.tcx(), trait_def_id);
         let matching_index =
             trait_items.iter()
-                       .position(|item| item.name() == self.method_name);
+                       .position(|item| item.name() == self.item_name);
         let matching_index = match matching_index {
             Some(i) => i,
             None => { return Ok(()); }
         };
-        let method = match (&*trait_items)[matching_index].as_opt_method() {
-            Some(m) => m,
-            None => { return Ok(()); }
-        };
+        let ref item = (&*trait_items)[matching_index];
 
         // Check whether `trait_def_id` defines a method with suitable name:
-        if !self.has_applicable_self(&*method) {
+        if !self.has_applicable_self(item) {
             debug!("method has inapplicable self");
             self.record_static_candidate(TraitSource(trait_def_id));
             return Ok(());
         }
 
         self.assemble_extension_candidates_for_trait_impls(trait_def_id,
-                                                           method.clone(),
+                                                           item.clone(),
                                                            matching_index);
 
         try!(self.assemble_closure_candidates(trait_def_id,
-                                              method.clone(),
+                                              item.clone(),
                                               matching_index));
 
         self.assemble_projection_candidates(trait_def_id,
-                                            method.clone(),
+                                            item.clone(),
                                             matching_index);
 
         self.assemble_where_clause_candidates(trait_def_id,
-                                              method,
+                                              item.clone(),
                                               matching_index);
 
         Ok(())
@@ -622,8 +621,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_extension_candidates_for_trait_impls(&mut self,
                                                      trait_def_id: ast::DefId,
-                                                     method: Rc<ty::Method<'tcx>>,
-                                                     method_index: usize)
+                                                     item: ty::ImplOrTraitItem<'tcx>,
+                                                     item_index: usize)
     {
         ty::populate_implementations_for_trait_if_necessary(self.tcx(),
                                                             trait_def_id);
@@ -657,7 +656,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
             // Determine the receiver type that the method itself expects.
             let xform_self_ty =
-                self.xform_self_ty(&method,
+                self.xform_self_ty(&item,
                                    impl_trait_ref.self_ty(),
                                    impl_trait_ref.substs);
 
@@ -665,8 +664,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method.clone(),
-                kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, method_index)
+                item: item.clone(),
+                kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
             });
         }
     }
@@ -689,8 +688,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_closure_candidates(&mut self,
                                    trait_def_id: ast::DefId,
-                                   method_ty: Rc<ty::Method<'tcx>>,
-                                   method_index: usize)
+                                   item: ty::ImplOrTraitItem<'tcx>,
+                                   item_index: usize)
                                    -> Result<(),MethodError>
     {
         // Check if this is one of the Fn,FnMut,FnOnce traits.
@@ -736,13 +735,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                                              &trait_def.generics,
                                                              step.self_ty);
 
-            let xform_self_ty = self.xform_self_ty(&method_ty,
+            let xform_self_ty = self.xform_self_ty(&item,
                                                    step.self_ty,
                                                    &substs);
             self.inherent_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method_ty.clone(),
-                kind: ClosureCandidate(trait_def_id, method_index)
+                item: item.clone(),
+                kind: ClosureCandidate(trait_def_id, item_index)
             });
         }
 
@@ -751,16 +750,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_projection_candidates(&mut self,
                                       trait_def_id: ast::DefId,
-                                      method: Rc<ty::Method<'tcx>>,
-                                      method_index: usize)
+                                      item: ty::ImplOrTraitItem<'tcx>,
+                                      item_index: usize)
     {
         debug!("assemble_projection_candidates(\
                trait_def_id={}, \
-               method={}, \
-               method_index={})",
+               item={}, \
+               item_index={})",
                trait_def_id.repr(self.tcx()),
-               method.repr(self.tcx()),
-               method_index);
+               item.repr(self.tcx()),
+               item_index);
 
         for step in &*self.steps {
             debug!("assemble_projection_candidates: step={}",
@@ -792,7 +791,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                        bound.repr(self.tcx()));
 
                 if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
-                    let xform_self_ty = self.xform_self_ty(&method,
+                    let xform_self_ty = self.xform_self_ty(&item,
                                                            bound.self_ty(),
                                                            bound.substs);
 
@@ -802,8 +801,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
                     self.extension_candidates.push(Candidate {
                         xform_self_ty: xform_self_ty,
-                        method_ty: method.clone(),
-                        kind: ProjectionCandidate(trait_def_id, method_index)
+                        item: item.clone(),
+                        kind: ProjectionCandidate(trait_def_id, item_index)
                     });
                 }
             }
@@ -812,8 +811,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
     fn assemble_where_clause_candidates(&mut self,
                                         trait_def_id: ast::DefId,
-                                        method_ty: Rc<ty::Method<'tcx>>,
-                                        method_index: usize)
+                                        item: ty::ImplOrTraitItem<'tcx>,
+                                        item_index: usize)
     {
         debug!("assemble_where_clause_candidates(trait_def_id={})",
                trait_def_id.repr(self.tcx()));
@@ -824,7 +823,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                           .filter(|b| b.def_id() == trait_def_id)
         {
             let bound = self.erase_late_bound_regions(&poly_bound);
-            let xform_self_ty = self.xform_self_ty(&method_ty,
+            let xform_self_ty = self.xform_self_ty(&item,
                                                    bound.self_ty(),
                                                    bound.substs);
 
@@ -834,8 +833,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
 
             self.extension_candidates.push(Candidate {
                 xform_self_ty: xform_self_ty,
-                method_ty: method_ty.clone(),
-                kind: WhereClauseCandidate(poly_bound, method_index)
+                item: item.clone(),
+                kind: WhereClauseCandidate(poly_bound, item_index)
             });
         }
     }
@@ -860,7 +859,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         try!(self.assemble_extension_candidates_for_all_traits());
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.method_ty.container.id()],
+            Some(Ok(p)) => vec![p.item.container().id()],
             Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
                 match source {
                     TraitSource(id) => id,
@@ -1099,11 +1098,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         }
 
         // If so, just use this trait and call it a day.
-        let (trait_def_id, method_num) = trait_data;
-        let method_ty = probes[0].method_ty.clone();
+        let (trait_def_id, item_num) = trait_data;
+        let item = probes[0].item.clone();
         Some(Pick {
-            method_ty: method_ty,
-            kind: TraitPick(trait_def_id, method_num),
+            item: item,
+            kind: TraitPick(trait_def_id, item_num),
             autoderefs: 0,
             autoref: None,
             unsize: None
@@ -1117,28 +1116,25 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
         self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
     }
 
-    fn has_applicable_self(&self, method: &ty::Method) -> bool {
+    fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
         // "fast track" -- check for usage of sugar
-        match method.explicit_self {
-            ty::StaticExplicitSelfCategory => {
-                if self.mode == Mode::Path {
-                    return true;
-                }
-            }
-            ty::ByValueExplicitSelfCategory |
-            ty::ByReferenceExplicitSelfCategory(..) |
-            ty::ByBoxExplicitSelfCategory => {
-                return true;
-            }
+        match *item {
+            ty::ImplOrTraitItem::MethodTraitItem(ref method) =>
+                match method.explicit_self {
+                    ty::StaticExplicitSelfCategory => self.mode == Mode::Path,
+                    ty::ByValueExplicitSelfCategory |
+                    ty::ByReferenceExplicitSelfCategory(..) |
+                    ty::ByBoxExplicitSelfCategory => true,
+                },
+            ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
+            _ => false,
         }
-
         // FIXME -- check for types that deref to `Self`,
         // like `Rc<Self>` and so on.
         //
         // Note also that the current code will break if this type
         // includes any of the type parameters defined on the method
         // -- but this could be overcome.
-        return false;
     }
 
     fn record_static_candidate(&mut self, source: CandidateSource) {
@@ -1146,11 +1142,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     }
 
     fn xform_self_ty(&self,
-                     method: &Rc<ty::Method<'tcx>>,
+                     item: &ty::ImplOrTraitItem<'tcx>,
                      impl_ty: Ty<'tcx>,
                      substs: &subst::Substs<'tcx>)
                      -> Ty<'tcx>
     {
+        match item.as_opt_method() {
+            Some(ref method) => self.xform_method_self_ty(method, impl_ty,
+                                                          substs),
+            None => impl_ty,
+        }
+    }
+
+    fn xform_method_self_ty(&self,
+                            method: &Rc<ty::Method<'tcx>>,
+                            impl_ty: Ty<'tcx>,
+                            substs: &subst::Substs<'tcx>)
+                            -> Ty<'tcx>
+    {
         debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
                impl_ty.repr(self.tcx()),
                method.fty.sig.0.inputs.get(0).repr(self.tcx()),
@@ -1245,46 +1254,45 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
     }
 }
 
-fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                     impl_def_id: ast::DefId,
-                     method_name: ast::Name)
-                     -> Option<Rc<ty::Method<'tcx>>>
+fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+                   impl_def_id: ast::DefId,
+                   item_name: ast::Name)
+                   -> Option<ty::ImplOrTraitItem<'tcx>>
 {
     let impl_items = tcx.impl_items.borrow();
     let impl_items = impl_items.get(&impl_def_id).unwrap();
     impl_items
         .iter()
         .map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
-        .find(|m| m.name() == method_name)
-        .and_then(|item| item.as_opt_method())
+        .find(|item| item.name() == item_name)
 }
 
-/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
-/// index (or `None`, if no such method).
-fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                      trait_def_id: ast::DefId,
-                      method_name: ast::Name)
-                      -> Option<(usize, Rc<ty::Method<'tcx>>)>
+/// Find item with name `item_name` defined in `trait_def_id` and return it,
+/// along with its index (or `None`, if no such item).
+fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
+                    trait_def_id: ast::DefId,
+                    item_name: ast::Name)
+                    -> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
 {
     let trait_items = ty::trait_items(tcx, trait_def_id);
     debug!("trait_method; items: {:?}", trait_items);
     trait_items
         .iter()
         .enumerate()
-        .find(|&(_, ref item)| item.name() == method_name)
-        .and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
+        .find(|&(_, ref item)| item.name() == item_name)
+        .map(|(num, ref item)| (num, (*item).clone()))
 }
 
 impl<'tcx> Candidate<'tcx> {
     fn to_unadjusted_pick(&self) -> Pick<'tcx> {
         Pick {
-            method_ty: self.method_ty.clone(),
+            item: self.item.clone(),
             kind: match self.kind {
                 InherentImplCandidate(def_id, _) => {
                     InherentImplPick(def_id)
                 }
-                ObjectCandidate(def_id, method_num, real_index) => {
-                    ObjectPick(def_id, method_num, real_index)
+                ObjectCandidate(def_id, item_num, real_index) => {
+                    ObjectPick(def_id, item_num, real_index)
                 }
                 ExtensionImplCandidate(def_id, _, _, index) => {
                     ExtensionImplPick(def_id, index)
@@ -1323,25 +1331,25 @@ impl<'tcx> Candidate<'tcx> {
         }
     }
 
-    fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
+    fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
         match self.kind {
             InherentImplCandidate(..) => {
                 None
             }
-            ObjectCandidate(trait_def_id, method_num, _) => {
-                Some((trait_def_id, method_num))
+            ObjectCandidate(trait_def_id, item_num, _) => {
+                Some((trait_def_id, item_num))
             }
-            ClosureCandidate(trait_def_id, method_num) => {
-                Some((trait_def_id, method_num))
+            ClosureCandidate(trait_def_id, item_num) => {
+                Some((trait_def_id, item_num))
             }
-            ExtensionImplCandidate(_, ref trait_ref, _, method_num) => {
-                Some((trait_ref.def_id, method_num))
+            ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
+                Some((trait_ref.def_id, item_num))
             }
-            WhereClauseCandidate(ref trait_ref, method_num) => {
-                Some((trait_ref.def_id(), method_num))
+            WhereClauseCandidate(ref trait_ref, item_num) => {
+                Some((trait_ref.def_id(), item_num))
             }
-            ProjectionCandidate(trait_def_id, method_num) => {
-                Some((trait_def_id, method_num))
+            ProjectionCandidate(trait_def_id, item_num) => {
+                Some((trait_def_id, item_num))
             }
         }
     }
@@ -1392,9 +1400,9 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
 
 impl<'tcx> Repr<'tcx> for Pick<'tcx> {
     fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
-        format!("Pick(method_ty={}, autoderefs={},
+        format!("Pick(item={}, autoderefs={},
                  autoref={}, unsize={}, kind={:?})",
-                self.method_ty.repr(tcx),
+                self.item.repr(tcx),
                 self.autoderefs,
                 self.autoref.repr(tcx),
                 self.unsize.repr(tcx),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 47388e0e558..d04205666f2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -78,7 +78,7 @@ type parameter).
 
 pub use self::LvaluePreference::*;
 pub use self::Expectation::*;
-pub use self::compare_method::compare_impl_method;
+pub use self::compare_method::{compare_impl_method, compare_const_impl};
 use self::TupleArgumentsFlag::*;
 
 use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
@@ -808,7 +808,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
 
         for impl_item in impl_items {
             match impl_item.node {
-                ast::ConstImplItem(_, _) => {}
+                ast::ConstImplItem(_, ref expr) => {
+                    check_const(ccx, impl_item.span, &*expr, impl_item.id)
+                }
                 ast::MethodImplItem(ref sig, ref body) => {
                     check_method_body(ccx, &impl_pty.generics, sig, body,
                                       impl_item.id, impl_item.span);
@@ -824,15 +826,15 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
         let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
         for trait_item in trait_items {
             match trait_item.node {
-                ast::ConstTraitItem(_, _) => {}
-                ast::MethodTraitItem(_, None) => {
-                    // Nothing to do, since required methods don't have
-                    // bodies to check.
+                ast::ConstTraitItem(_, Some(ref expr)) => {
+                    check_const(ccx, trait_item.span, &*expr, trait_item.id)
                 }
                 ast::MethodTraitItem(ref sig, Some(ref body)) => {
                     check_method_body(ccx, &trait_def.generics, sig, body,
                                       trait_item.id, trait_item.span);
                 }
+                ast::ConstTraitItem(_, None) |
+                ast::MethodTraitItem(_, None) |
                 ast::TypeTraitItem(..) => {
                     // Nothing to do.
                 }
@@ -922,7 +924,48 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     // and compatible with trait signature
     for impl_item in impl_items {
         match impl_item.node {
-            ast::ConstImplItem(_, _) => {}
+            ast::ConstImplItem(..) => {
+                let impl_const_def_id = local_def(impl_item.id);
+                let impl_const_ty = ty::impl_or_trait_item(ccx.tcx,
+                                                           impl_const_def_id);
+
+                // Find associated const definition.
+                let opt_associated_const =
+                    trait_items.iter()
+                               .find(|ac| ac.name() == impl_const_ty.name());
+                match opt_associated_const {
+                    Some(associated_const) => {
+                        match (associated_const, &impl_const_ty) {
+                            (&ty::ConstTraitItem(ref const_trait),
+                             &ty::ConstTraitItem(ref const_impl)) => {
+                                compare_const_impl(ccx.tcx,
+                                                   &const_impl,
+                                                   impl_item.span,
+                                                   &const_trait,
+                                                   &*impl_trait_ref);
+                            }
+                            _ => {
+                                span_err!(tcx.sess, impl_item.span, E0323,
+                                          "item `{}` is an associated const, \
+                                          which doesn't match its trait `{}`",
+                                          token::get_name(impl_const_ty.name()),
+                                          impl_trait_ref.repr(tcx))
+                            }
+                        }
+                    }
+                    None => {
+                        // This is `span_bug` as it should have already been
+                        // caught in resolve.
+                        tcx.sess.span_bug(
+                            impl_item.span,
+                            &format!(
+                                "associated const `{}` is not a member of \
+                                 trait `{}`",
+                                token::get_name(impl_const_ty.name()),
+                                impl_trait_ref.repr(tcx)));
+                    }
+                }
+            }
             ast::MethodImplItem(_, ref body) => {
                 let impl_method_def_id = local_def(impl_item.id);
                 let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
@@ -946,13 +989,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                     &*impl_trait_ref);
                             }
                             _ => {
-                                // This is span_bug as it should have already been
-                                // caught in resolve.
-                                tcx.sess.span_bug(
-                                    impl_item.span,
-                                    &format!("item `{}` is of a different kind from its trait `{}`",
-                                             token::get_name(impl_item_ty.name()),
-                                             impl_trait_ref.repr(tcx)));
+                                span_err!(tcx.sess, impl_item.span, E0324,
+                                          "item `{}` is an associated method, \
+                                          which doesn't match its trait `{}`",
+                                          token::get_name(impl_item_ty.name()),
+                                          impl_trait_ref.repr(tcx))
                             }
                         }
                     }
@@ -982,11 +1023,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         match (associated_type, &typedef_ty) {
                             (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
                             _ => {
-                                // Formerly `span_bug`, but it turns out that
-                                // this is not checked in resolve, so this is
-                                // the first place where we'll notice the
-                                // mismatch.
-                                span_err!(tcx.sess, impl_item.span, E0323,
+                                span_err!(tcx.sess, impl_item.span, E0325,
                                           "item `{}` is an associated type, \
                                           which doesn't match its trait `{}`",
                                           token::get_name(typedef_ty.name()),
@@ -1014,10 +1051,27 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     // Check for missing items from trait
     let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
+    let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
     let mut missing_methods = Vec::new();
     for trait_item in &*trait_items {
         match *trait_item {
-            ty::ConstTraitItem(_) => {}
+            ty::ConstTraitItem(ref associated_const) => {
+                let is_implemented = impl_items.iter().any(|ii| {
+                    match ii.node {
+                        ast::ConstImplItem(..) => {
+                            ii.ident.name == associated_const.name
+                        }
+                        _ => false,
+                    }
+                });
+                let is_provided =
+                    associated_consts.iter().any(|ac| ac.default.is_some() &&
+                                                 ac.name == associated_const.name);
+                if !is_implemented && !is_provided {
+                    missing_methods.push(format!("`{}`",
+                                                 token::get_name(associated_const.name)));
+                }
+            }
             ty::MethodTraitItem(ref trait_method) => {
                 let is_implemented =
                     impl_items.iter().any(|ii| {
@@ -4254,7 +4308,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     // Luckily, we can (at least for now) deduce the intermediate steps
     // just from the end-point.
     //
-    // There are basically three cases to consider:
+    // There are basically four cases to consider:
     //
     // 1. Reference to a *type*, such as a struct or enum:
     //
@@ -4304,6 +4358,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     //    `SomeStruct::<A>`, contains parameters in TypeSpace, and the
     //    final segment, `foo::<B>` contains parameters in fn space.
     //
+    // 4. Reference to an *associated const*:
+    //
+    // impl<A> AnotherStruct<A> {
+    // const FOO: B = BAR;
+    // }
+    //
+    // The path in this case will look like
+    // `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
+    // only will have parameters in TypeSpace.
+    //
     // The first step then is to categorize the segments appropriately.
 
     assert!(!segments.is_empty());
@@ -4355,8 +4419,21 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
             }
         }
 
-        def::DefAssociatedConst(..) => {
-            segment_spaces = repeat(None).take(segments.len()).collect();
+        def::DefAssociatedConst(_, provenance) => {
+            match provenance {
+                def::FromTrait(trait_did) => {
+                    callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
+                }
+                def::FromImpl(_) => {}
+            }
+
+            if segments.len() >= 2 {
+                segment_spaces = repeat(None).take(segments.len() - 2).collect();
+                segment_spaces.push(Some(subst::TypeSpace));
+                segment_spaces.push(None);
+            } else {
+                segment_spaces = vec![None];
+            }
         }
 
         // Other cases. Various nonsense that really shouldn't show up
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index d04e447a460..8bb0596753c 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -691,11 +691,37 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
+fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                      container: ImplOrTraitItemContainer,
+                                      ident: ast::Ident,
+                                      id: ast::NodeId,
+                                      vis: ast::Visibility,
+                                      ty: ty::Ty<'tcx>,
+                                      default: Option<&ast::Expr>)
+{
+    ccx.tcx.predicates.borrow_mut().insert(local_def(id),
+                                           ty::GenericPredicates::empty());
+
+    write_ty_to_tcx(ccx.tcx, id, ty);
+    let default_id = default.map(|expr| local_def(expr.id));
+
+    let associated_const = Rc::new(ty::AssociatedConst {
+        name: ident.name,
+        vis: vis,
+        def_id: local_def(id),
+        container: container,
+        ty: ty,
+        default: default_id,
+    });
+    ccx.tcx.impl_or_trait_items.borrow_mut()
+       .insert(local_def(id), ty::ConstTraitItem(associated_const));
+}
+
 fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                     container: ImplOrTraitItemContainer,
-                                     ident: ast::Ident,
-                                     id: ast::NodeId,
-                                     vis: ast::Visibility)
+                                 container: ImplOrTraitItemContainer,
+                                 ident: ast::Ident,
+                                 id: ast::NodeId,
+                                 vis: ast::Visibility)
 {
     let associated_type = Rc::new(ty::AssociatedType {
         name: ident.name,
@@ -828,6 +854,23 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
                 it.vis
             };
 
+            // Convert all the associated consts.
+            for impl_item in impl_items {
+                if let ast::ConstImplItem(ref ty, ref expr) = impl_item.node {
+                    let ty = ccx.icx(&ty_predicates)
+                                .to_ty(&ExplicitRscope, &*ty);
+                    tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
+                                                   TypeScheme {
+                                                       generics: ty_generics.clone(),
+                                                       ty: ty,
+                                                   });
+                    convert_associated_const(ccx, ImplContainer(local_def(it.id)),
+                                             impl_item.ident, impl_item.id,
+                                             impl_item.vis.inherit_from(parent_visibility),
+                                             ty, Some(&*expr));
+                }
+            }
+
             // Convert all the associated types.
             for impl_item in impl_items {
                 if let ast::TypeImplItem(ref ty) = impl_item.node {
@@ -909,6 +952,25 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
             // Convert all the associated types.
             for trait_item in trait_items {
                 match trait_item.node {
+                    ast::ConstTraitItem(ref ty, ref default) => {
+                        let ty = ccx.icx(&trait_predicates)
+                                    .to_ty(&ExplicitRscope, ty);
+                        tcx.tcache.borrow_mut().insert(local_def(trait_item.id),
+                                                       TypeScheme {
+                                                           generics: trait_def.generics.clone(),
+                                                           ty: ty,
+                                                       });
+                        convert_associated_const(ccx, TraitContainer(local_def(it.id)),
+                                                 trait_item.ident, trait_item.id,
+                                                 ast::Public, ty, default.as_ref().map(|d| &**d));
+                    }
+                    _ => {}
+                }
+            };
+
+            // Convert all the associated types.
+            for trait_item in trait_items {
+                match trait_item.node {
                     ast::TypeTraitItem(..) => {
                         as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
                                                 trait_item.ident, trait_item.id, ast::Public);
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index b17a7f4f318..a4814b36fe5 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -176,7 +176,10 @@ register_diagnostics! {
     E0320, // recursive overflow during dropck
     E0321, // extended coherence rules for defaulted traits violated
     E0322, // cannot implement Sized explicitly
-    E0323, // implemented trait where method should have been provided
+    E0323, // implemented an associated const when another trait item expected
+    E0324, // implemented a method when another trait item expected
+    E0325, // implemented an associated type when another trait item expected
+    E0326, // associated const implemented with different type from trait
     E0366, // dropck forbid specialization to concrete type or region
     E0367, // dropck forbid specialization to predicate not in struct/enum
     E0368, // binary operation `<op>=` cannot be applied to types
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 0bc3da416cb..0d59577a6d8 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -22,12 +22,13 @@ use rustc::middle::def;
 use rustc::middle::ty;
 use rustc::middle::subst;
 use rustc::middle::stability;
+use rustc::middle::const_eval;
 
 use core::DocContext;
 use doctree;
 use clean;
 
-use super::Clean;
+use super::{Clean, ToSource};
 
 /// Attempt to inline the definition of a local node id into this AST.
 ///
@@ -106,7 +107,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
             record_extern_fqn(cx, did, clean::TypeStatic);
             clean::StaticItem(build_static(cx, tcx, did, mtbl))
         }
-        def::DefConst(did) => {
+        def::DefConst(did) | def::DefAssociatedConst(did, _) => {
             record_extern_fqn(cx, did, clean::TypeConst);
             clean::ConstantItem(build_const(cx, tcx, did))
         }
@@ -312,7 +313,27 @@ pub fn build_impl(cx: &DocContext,
         let did = did.def_id();
         let impl_item = ty::impl_or_trait_item(tcx, did);
         match impl_item {
-            ty::ConstTraitItem(_) => { return None }
+            ty::ConstTraitItem(ref assoc_const) => {
+                let did = assoc_const.def_id;
+                let type_scheme = ty::lookup_item_type(tcx, did);
+                let default = match assoc_const.default {
+                    Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None)
+                                               .unwrap().span.to_src(cx)),
+                    None => None,
+                };
+                Some(clean::Item {
+                    name: Some(assoc_const.name.clean(cx)),
+                    inner: clean::AssociatedConstItem(
+                        type_scheme.ty.clean(cx),
+                        default,
+                    ),
+                    source: clean::Span::empty(),
+                    attrs: vec![],
+                    visibility: None,
+                    stability: stability::lookup(tcx, did).clean(cx),
+                    def_id: did
+                })
+            }
             ty::MethodTraitItem(method) => {
                 if method.vis != ast::Public && associated_trait.is_none() {
                     return None
@@ -444,7 +465,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt,
     use rustc::middle::const_eval;
     use syntax::print::pprust;
 
-    let expr = const_eval::lookup_const_by_id(tcx, did).unwrap_or_else(|| {
+    let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 447cf7eab45..3d1e47345d4 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1904,6 +1904,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     Ok(())
 }
 
+fn assoc_const(w: &mut fmt::Formatter, it: &clean::Item,
+               ty: &clean::Type, default: &Option<String>)
+               -> fmt::Result {
+    try!(write!(w, "const {}", it.name.as_ref().unwrap()));
+    try!(write!(w, ": {}", ty));
+    if let Some(ref default) = *default {
+        try!(write!(w, " = {}", default));
+    }
+    Ok(())
+}
+
 fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
               bounds: &Vec<clean::TyParamBound>,
               default: &Option<clean::Type>)
@@ -1959,7 +1970,9 @@ fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
             method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
                    link)
         }
-        clean::AssociatedConstItem(_, _) => Ok(()),
+        clean::AssociatedConstItem(ref ty, ref default) => {
+            assoc_const(w, meth, ty, default)
+        }
         clean::AssociatedTypeItem(ref bounds, ref default) => {
             assoc_type(w, meth, bounds, default)
         }
@@ -2319,7 +2332,14 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
                 try!(write!(w, "type {} = {}", name, tydef.type_));
                 try!(write!(w, "</code></h4>\n"));
             }
-            clean::AssociatedConstItem(_, _) => {}
+            clean::AssociatedConstItem(ref ty, ref default) => {
+                let name = item.name.as_ref().unwrap();
+                try!(write!(w, "<h4 id='assoc_const.{}' class='{}'><code>",
+                            *name,
+                            shortty(item)));
+                try!(assoc_const(w, item, ty, default));
+                try!(write!(w, "</code></h4>\n"));
+            }
             clean::AssociatedTypeItem(ref bounds, ref default) => {
                 let name = item.name.as_ref().unwrap();
                 try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index dc577f603f6..9a1c963b8eb 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -17,8 +17,8 @@ use ast::{Public, Unsafety};
 use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
 use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, DefaultReturn};
+use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
 use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
@@ -1158,6 +1158,20 @@ impl<'a> Parser<'a> {
                 let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
                 try!(p.expect(&token::Semi));
                 (ident, TypeTraitItem(bounds, default))
+            } else if try!(p.eat_keyword(keywords::Const)) {
+                let ident = try!(p.parse_ident());
+                try!(p.expect(&token::Colon));
+                let ty = try!(p.parse_ty_sum());
+                let default = if p.check(&token::Eq) {
+                    try!(p.bump());
+                    let expr = try!(p.parse_expr_nopanic());
+                    try!(p.commit_expr_expecting(&expr, token::Semi));
+                    Some(expr)
+                } else {
+                    try!(p.expect(&token::Semi));
+                    None
+                };
+                (ident, ConstTraitItem(ty, default))
             } else {
                 let style = try!(p.parse_unsafety());
                 let abi = if try!(p.eat_keyword(keywords::Extern)) {
@@ -4313,6 +4327,14 @@ impl<'a> Parser<'a> {
             let typ = try!(self.parse_ty_sum());
             try!(self.expect(&token::Semi));
             (name, TypeImplItem(typ))
+        } else if try!(self.eat_keyword(keywords::Const)) {
+            let name = try!(self.parse_ident());
+            try!(self.expect(&token::Colon));
+            let typ = try!(self.parse_ty_sum());
+            try!(self.expect(&token::Eq));
+            let expr = try!(self.parse_expr_nopanic());
+            try!(self.commit_expr_expecting(&expr, token::Semi));
+            (name, ConstImplItem(typ, expr))
         } else {
             let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
             attrs.extend(inner_attrs.into_iter());
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6fd2a8b1815..4cfb9e4147a 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -796,6 +796,26 @@ impl<'a> State<'a> {
         }
     }
 
+    fn print_associated_const(&mut self,
+                              ident: ast::Ident,
+                              ty: &ast::Ty,
+                              default: Option<&ast::Expr>,
+                              vis: ast::Visibility)
+                              -> io::Result<()>
+    {
+        try!(word(&mut self.s, &visibility_qualified(vis, "")));
+        try!(self.word_space("const"));
+        try!(self.print_ident(ident));
+        try!(self.word_space(":"));
+        try!(self.print_type(ty));
+        if let Some(expr) = default {
+            try!(space(&mut self.s));
+            try!(self.word_space("="));
+            try!(self.print_expr(expr));
+        }
+        word(&mut self.s, ";")
+    }
+
     fn print_associated_type(&mut self,
                              ident: ast::Ident,
                              bounds: Option<&ast::TyParamBounds>,
@@ -1269,7 +1289,11 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(ti.span.lo));
         try!(self.print_outer_attributes(&ti.attrs));
         match ti.node {
-            ast::ConstTraitItem(_, _) => Ok(()),
+            ast::ConstTraitItem(ref ty, ref default) => {
+                try!(self.print_associated_const(ti.ident, &ty,
+                                                 default.as_ref().map(|expr| &**expr),
+                                                 ast::Inherited));
+            }
             ast::MethodTraitItem(ref sig, ref body) => {
                 if body.is_some() {
                     try!(self.head(""));
@@ -1296,7 +1320,9 @@ impl<'a> State<'a> {
         try!(self.maybe_print_comment(ii.span.lo));
         try!(self.print_outer_attributes(&ii.attrs));
         match ii.node {
-            ast::ConstImplItem(_, _) => Ok(()),
+            ast::ConstImplItem(ref ty, ref expr) => {
+                try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
+            }
             ast::MethodImplItem(ref sig, ref body) => {
                 try!(self.head(""));
                 try!(self.print_method_sig(ii.ident, sig, ii.vis));
diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs
new file mode 100644
index 00000000000..1d74873a5d5
--- /dev/null
+++ b/src/test/compile-fail/associated-const-private-impl.rs
@@ -0,0 +1,27 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+mod bar1 {
+    pub use self::bar2::Foo;
+    mod bar2 {
+        pub struct Foo;
+
+        impl Foo {
+            const ID: i32 = 1;
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(1, bar1::Foo::ID);
+    //~^ERROR associated const `ID` is private
+}
diff --git a/src/test/compile-fail/impl-type-where-trait-has-method.rs b/src/test/compile-fail/impl-type-where-trait-has-method.rs
new file mode 100644
index 00000000000..eb75b82424d
--- /dev/null
+++ b/src/test/compile-fail/impl-type-where-trait-has-method.rs
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+trait Foo {
+    fn bar(&self);
+}
+
+impl Foo for u32 {
+    //~^ ERROR not all trait items implemented, missing: `bar`
+    type bar = u64;
+    //~^ ERROR item `bar` is an associated type, which doesn't match its trait `Foo`
+}
+
+fn main () {}
diff --git a/src/test/parse-fail/issue-20711-2.rs b/src/test/parse-fail/issue-20711-2.rs
index 2c993b7654e..be6bd516d6f 100644
--- a/src/test/parse-fail/issue-20711-2.rs
+++ b/src/test/parse-fail/issue-20711-2.rs
@@ -16,6 +16,6 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
 
 fn main() {}
diff --git a/src/test/parse-fail/issue-20711.rs b/src/test/parse-fail/issue-20711.rs
index 8462bd8fd01..d1d8d3acf91 100644
--- a/src/test/parse-fail/issue-20711.rs
+++ b/src/test/parse-fail/issue-20711.rs
@@ -14,6 +14,6 @@ struct Foo;
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
+} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
 
 fn main() {}
diff --git a/src/test/parse-fail/issue-21153.rs b/src/test/parse-fail/issue-21153.rs
index 44d979ba979..76a4687f544 100644
--- a/src/test/parse-fail/issue-21153.rs
+++ b/src/test/parse-fail/issue-21153.rs
@@ -11,5 +11,5 @@
 // compile-flags: -Z parse-only
 
 trait MyTrait<T>: Iterator {
-    Item = T; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `Item`
+    Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
 }
diff --git a/src/test/parse-fail/removed-syntax-static-fn.rs b/src/test/parse-fail/removed-syntax-static-fn.rs
index be1e89dd717..7b6caad86b6 100644
--- a/src/test/parse-fail/removed-syntax-static-fn.rs
+++ b/src/test/parse-fail/removed-syntax-static-fn.rs
@@ -14,5 +14,5 @@ struct S;
 
 impl S {
     static fn f() {}
-    //~^ ERROR expected one of `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
 }
+//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs
new file mode 100644
index 00000000000..adce0d7bbf4
--- /dev/null
+++ b/src/test/parse-fail/trait-pub-assoc-const.rs
@@ -0,0 +1,16 @@
+// Copyright 2015 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.
+
+trait Foo {
+    pub const Foo: u32;
+     //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
+}
+
+fn main() {}
diff --git a/src/test/parse-fail/trait-pub-assoc-ty.rs b/src/test/parse-fail/trait-pub-assoc-ty.rs
index 02d76234d4e..dab6c433aba 100644
--- a/src/test/parse-fail/trait-pub-assoc-ty.rs
+++ b/src/test/parse-fail/trait-pub-assoc-ty.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 trait Foo {
-    pub type Foo; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+    pub type Foo;
+    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
 }
 
 fn main() {}
diff --git a/src/test/parse-fail/trait-pub-method.rs b/src/test/parse-fail/trait-pub-method.rs
index e76802d2ea0..7cb9363830c 100644
--- a/src/test/parse-fail/trait-pub-method.rs
+++ b/src/test/parse-fail/trait-pub-method.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 trait Foo {
-    pub fn foo(); //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
+    pub fn foo();
+    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
 }
 
 fn main() {}
diff --git a/src/test/run-pass/associated-const-inherent-impl.rs b/src/test/run-pass/associated-const-inherent-impl.rs
new file mode 100644
index 00000000000..71f7a925d55
--- /dev/null
+++ b/src/test/run-pass/associated-const-inherent-impl.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+struct Foo;
+
+impl Foo {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, Foo::ID);
+}
diff --git a/src/test/run-pass/associated-const-overwrite-default.rs b/src/test/run-pass/associated-const-overwrite-default.rs
new file mode 100644
index 00000000000..26ece859e14
--- /dev/null
+++ b/src/test/run-pass/associated-const-overwrite-default.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+trait Foo: MarkerTrait {
+    const ID: i32 = 2;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}
diff --git a/src/test/run-pass/associated-const-public-impl.rs b/src/test/run-pass/associated-const-public-impl.rs
new file mode 100644
index 00000000000..08676425a51
--- /dev/null
+++ b/src/test/run-pass/associated-const-public-impl.rs
@@ -0,0 +1,26 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+mod bar1 {
+    pub use self::bar2::Foo;
+    mod bar2 {
+        pub struct Foo;
+
+        impl Foo {
+            pub const ID: i32 = 1;
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(1, bar1::Foo::ID);
+}
diff --git a/src/test/run-pass/associated-const-self-type.rs b/src/test/run-pass/associated-const-self-type.rs
new file mode 100644
index 00000000000..b4fb452e020
--- /dev/null
+++ b/src/test/run-pass/associated-const-self-type.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+trait MyInt: MarkerTrait {
+    const ONE: Self;
+}
+
+impl MyInt for i32 {
+    const ONE: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32>::ONE);
+}
diff --git a/src/test/run-pass/associated-const-ufcs-infer-trait.rs b/src/test/run-pass/associated-const-ufcs-infer-trait.rs
new file mode 100644
index 00000000000..21e1159366d
--- /dev/null
+++ b/src/test/run-pass/associated-const-ufcs-infer-trait.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+trait Foo: MarkerTrait {
+    const ID: i32;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32>::ID);
+}
diff --git a/src/test/run-pass/associated-const-use-default.rs b/src/test/run-pass/associated-const-use-default.rs
new file mode 100644
index 00000000000..59c83e267db
--- /dev/null
+++ b/src/test/run-pass/associated-const-use-default.rs
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+trait Foo: MarkerTrait {
+    const ID: i32 = 1;
+}
+
+impl Foo for i32 {}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}
diff --git a/src/test/run-pass/associated-const.rs b/src/test/run-pass/associated-const.rs
new file mode 100644
index 00000000000..5e7cc12cf48
--- /dev/null
+++ b/src/test/run-pass/associated-const.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+use std::marker::MarkerTrait;
+
+trait Foo: MarkerTrait {
+    const ID: i32;
+}
+
+impl Foo for i32 {
+    const ID: i32 = 1;
+}
+
+fn main() {
+    assert_eq!(1, <i32 as Foo>::ID);
+}