diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 3525d46a1f2..1ad4611dc9e 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -239,6 +239,24 @@ pub fn collect_language_items(krate: &ast::Crate,
 
 lets_do_this! {
 //  Variant name,                    Name,                      Method name;
+    CharImplItem,                    "char",                    char_impl;
+    StrImplItem,                     "str",                     str_impl;
+    SliceImplItem,                   "slice",                   slice_impl;
+    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
+    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
+    I8ImplItem,                      "i8",                      i8_impl;
+    I16ImplItem,                     "i16",                     i16_impl;
+    I32ImplItem,                     "i32",                     i32_impl;
+    I64ImplItem,                     "i64",                     i64_impl;
+    IsizeImplItem,                   "isize",                   isize_impl;
+    U8ImplItem,                      "u8",                      u8_impl;
+    U16ImplItem,                     "u16",                     u16_impl;
+    U32ImplItem,                     "u32",                     u32_impl;
+    U64ImplItem,                     "u64",                     u64_impl;
+    UsizeImplItem,                   "usize",                   usize_impl;
+    F32ImplItem,                     "f32",                     f32_impl;
+    F64ImplItem,                     "f64",                     f64_impl;
+
     SendTraitLangItem,               "send",                    send_trait;
     SizedTraitLangItem,              "sized",                   sized_trait;
     CopyTraitLangItem,               "copy",                    copy_trait;
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 8705e56b094..c3e1879fca8 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -788,6 +788,9 @@ pub struct ctxt<'tcx> {
     /// is used for lazy resolution of traits.
     pub populated_external_traits: RefCell<DefIdSet>,
 
+    /// The set of external primitive inherent implementations that have been read.
+    pub populated_external_primitive_impls: RefCell<DefIdSet>,
+
     /// Borrows
     pub upvar_capture_map: RefCell<UpvarCaptureMap>,
 
@@ -2599,6 +2602,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
         used_mut_nodes: RefCell::new(NodeSet()),
         populated_external_types: RefCell::new(DefIdSet()),
         populated_external_traits: RefCell::new(DefIdSet()),
+        populated_external_primitive_impls: RefCell::new(DefIdSet()),
         upvar_capture_map: RefCell::new(FnvHashMap()),
         extern_const_statics: RefCell::new(DefIdMap()),
         extern_const_variants: RefCell::new(DefIdMap()),
@@ -5988,6 +5992,25 @@ pub fn record_trait_implementation(tcx: &ctxt,
     tcx.trait_impls.borrow_mut().insert(trait_def_id, Rc::new(RefCell::new(vec!(impl_def_id))));
 }
 
+/// Load primitive inherent implementations if necessary
+pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt, lang_def_id: ast::DefId) {
+    if lang_def_id.krate == LOCAL_CRATE {
+        return
+    }
+    if tcx.populated_external_primitive_impls.borrow().contains(&lang_def_id) {
+        return
+    }
+
+    debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", lang_def_id);
+
+    let impl_items = csearch::get_impl_items(&tcx.sess.cstore, lang_def_id);
+
+    // Store the implementation info.
+    tcx.impl_items.borrow_mut().insert(lang_def_id, impl_items);
+
+    tcx.populated_external_primitive_impls.borrow_mut().insert(lang_def_id);
+}
+
 /// Populates the type context with all the implementations for the given type
 /// if necessary.
 pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 718804d317f..1f7cc3bb647 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -289,11 +289,87 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             ty::ty_param(p) => {
                 self.assemble_inherent_candidates_from_param(self_ty, p);
             }
+            ty::ty_char => {
+                let lang_def_id = self.tcx().lang_items.char_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_str => {
+                let lang_def_id = self.tcx().lang_items.str_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_vec(_, None) => {
+                let lang_def_id = self.tcx().lang_items.slice_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
+                let lang_def_id = self.tcx().lang_items.const_ptr_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
+                let lang_def_id = self.tcx().lang_items.mut_ptr_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_int(ast::TyI8) => {
+                let lang_def_id = self.tcx().lang_items.i8_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_int(ast::TyI16) => {
+                let lang_def_id = self.tcx().lang_items.i16_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_int(ast::TyI32) => {
+                let lang_def_id = self.tcx().lang_items.i32_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_int(ast::TyI64) => {
+                let lang_def_id = self.tcx().lang_items.i64_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_int(ast::TyIs(_)) => {
+                let lang_def_id = self.tcx().lang_items.isize_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_uint(ast::TyU8) => {
+                let lang_def_id = self.tcx().lang_items.u8_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_uint(ast::TyU16) => {
+                let lang_def_id = self.tcx().lang_items.u16_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_uint(ast::TyU32) => {
+                let lang_def_id = self.tcx().lang_items.u32_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_uint(ast::TyU64) => {
+                let lang_def_id = self.tcx().lang_items.u64_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_uint(ast::TyUs(_)) => {
+                let lang_def_id = self.tcx().lang_items.usize_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_float(ast::TyF32) => {
+                let lang_def_id = self.tcx().lang_items.f32_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
+            ty::ty_float(ast::TyF64) => {
+                let lang_def_id = self.tcx().lang_items.f64_impl();
+                self.assemble_inherent_impl_for_primitive(lang_def_id);
+            }
             _ => {
             }
         }
     }
 
+    fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option<ast::DefId>) {
+        if let Some(impl_def_id) = lang_def_id {
+            ty::populate_implementations_for_primitive_if_necessary(self.tcx(), impl_def_id);
+
+            self.assemble_inherent_impl_probe(impl_def_id);
+        }
+    }
+
     fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) {
         // Read the inherent implementation candidates for this type from the
         // metadata if necessary.
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 5dfe80cfcb2..ab694d26b15 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -16,6 +16,7 @@ use middle::ty;
 use syntax::ast::{Item, ItemImpl};
 use syntax::ast;
 use syntax::ast_util;
+use syntax::codemap::Span;
 use syntax::visit;
 use util::ppaux::{Repr, UserString};
 
@@ -38,6 +39,23 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
         }
     }
 
+    fn check_primitive_impl(&self,
+                            impl_def_id: ast::DefId,
+                            lang_def_id: Option<ast::DefId>,
+                            lang: &str,
+                            ty: &str,
+                            span: Span) {
+        match lang_def_id {
+            Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
+            _ => {
+                self.tcx.sess.span_err(
+                    span,
+                    &format!("only a single inherent implementation marked with `#[lang = \"{}\"]` \
+                              is allowed for the `{}` primitive", lang, ty));
+            }
+        }
+    }
+
     /// Checks exactly one impl for orphan rules and other such
     /// restrictions.  In this fn, it can happen that multiple errors
     /// apply to a specific impl, so just return after reporting one
@@ -62,6 +80,125 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                     ty::ty_uniq(..) => {
                         self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap());
                     }
+                    ty::ty_char => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.char_impl(),
+                                                  "char",
+                                                  "char",
+                                                  item.span);
+                    }
+                    ty::ty_str => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.str_impl(),
+                                                  "str",
+                                                  "str",
+                                                  item.span);
+                    }
+                    ty::ty_vec(_, None) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.slice_impl(),
+                                                  "slice",
+                                                  "[T]",
+                                                  item.span);
+                    }
+                    ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.const_ptr_impl(),
+                                                  "const_ptr",
+                                                  "*const T",
+                                                  item.span);
+                    }
+                    ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.mut_ptr_impl(),
+                                                  "mut_ptr",
+                                                  "*mut T",
+                                                  item.span);
+                    }
+                    ty::ty_int(ast::TyI8) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.i8_impl(),
+                                                  "i8",
+                                                  "i8",
+                                                  item.span);
+                    }
+                    ty::ty_int(ast::TyI16) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.i16_impl(),
+                                                  "i16",
+                                                  "i16",
+                                                  item.span);
+                    }
+                    ty::ty_int(ast::TyI32) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.i32_impl(),
+                                                  "i32",
+                                                  "i32",
+                                                  item.span);
+                    }
+                    ty::ty_int(ast::TyI64) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.i64_impl(),
+                                                  "i64",
+                                                  "i64",
+                                                  item.span);
+                    }
+                    ty::ty_int(ast::TyIs(_)) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.isize_impl(),
+                                                  "isize",
+                                                  "isize",
+                                                  item.span);
+                    }
+                    ty::ty_uint(ast::TyU8) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.u8_impl(),
+                                                  "u8",
+                                                  "u8",
+                                                  item.span);
+                    }
+                    ty::ty_uint(ast::TyU16) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.u16_impl(),
+                                                  "u16",
+                                                  "u16",
+                                                  item.span);
+                    }
+                    ty::ty_uint(ast::TyU32) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.u32_impl(),
+                                                  "u32",
+                                                  "u32",
+                                                  item.span);
+                    }
+                    ty::ty_uint(ast::TyU64) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.u64_impl(),
+                                                  "u64",
+                                                  "u64",
+                                                  item.span);
+                    }
+                    ty::ty_uint(ast::TyUs(_)) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.usize_impl(),
+                                                  "usize",
+                                                  "usize",
+                                                  item.span);
+                    }
+                    ty::ty_float(ast::TyF32) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.f32_impl(),
+                                                  "f32",
+                                                  "f32",
+                                                  item.span);
+                    }
+                    ty::ty_float(ast::TyF64) => {
+                        self.check_primitive_impl(def_id,
+                                                  self.tcx.lang_items.f64_impl(),
+                                                  "f64",
+                                                  "f64",
+                                                  item.span);
+                    }
                     _ => {
                         span_err!(self.tcx.sess, item.span, E0118,
                                   "no base type found for inherent implementation; \
diff --git a/src/test/compile-fail/single-primitive-inherent-impl.rs b/src/test/compile-fail/single-primitive-inherent-impl.rs
new file mode 100644
index 00000000000..b2cfcfab78b
--- /dev/null
+++ b/src/test/compile-fail/single-primitive-inherent-impl.rs
@@ -0,0 +1,24 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![crate_type = "lib"]
+#![feature(lang_items)]
+#![feature(no_std)]
+#![no_std]
+
+// OK
+#[lang = "char"]
+impl char {}
+
+impl char {
+//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive
+}