diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 3e4a2542b270b..fb39f3ff141ae 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -32,6 +32,7 @@ use rustc_const_math::ConstInt;
 
 use rustc::mir::repr::Mir;
 
+use std::borrow::Cow;
 use std::cell::Ref;
 use std::io;
 use std::mem;
@@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
         read_f64 -> f64;
         read_f32 -> f32;
         read_char -> char;
-        read_str -> String;
+        read_str -> Cow<str>;
     }
 
     fn error(&mut self, err: &str) -> Self::Error {
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index 5e25c61bae995..6d1ce65b50432 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -199,6 +199,7 @@ use self::DecoderError::*;
 use self::ParserState::*;
 use self::InternalStackElement::*;
 
+use std::borrow::Cow;
 use std::collections::{HashMap, BTreeMap};
 use std::io::prelude::*;
 use std::io;
@@ -2081,9 +2082,7 @@ impl Decoder {
     pub fn new(json: Json) -> Decoder {
         Decoder { stack: vec![json] }
     }
-}
 
-impl Decoder {
     fn pop(&mut self) -> Json {
         self.stack.pop().unwrap()
     }
@@ -2182,8 +2181,11 @@ impl ::Decoder for Decoder {
         Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
     }
 
-    fn read_str(&mut self) -> DecodeResult<string::String> {
-        expect!(self.pop(), String)
+    fn read_str(&mut self) -> DecodeResult<Cow<str>> {
+        match self.pop() {
+            Json::String(v) => Ok(Cow::Owned(v)),
+            ref other => Err(ExpectedError(stringify!(String).to_string(), format!("{}", other))),
+        }
     }
 
     fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs
index e97834f63cee4..a2c0ca954472c 100644
--- a/src/libserialize/opaque.rs
+++ b/src/libserialize/opaque.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
+use std::borrow::Cow;
 use std::io::{self, Write};
 use serialize;
 
@@ -246,11 +247,11 @@ impl<'a> serialize::Decoder for Decoder<'a> {
         Ok(::std::char::from_u32(bits).unwrap())
     }
 
-    fn read_str(&mut self) -> Result<String, Self::Error> {
+    fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
         let len = self.read_usize()?;
         let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
         self.position += len;
-        Ok(s.to_string())
+        Ok(Cow::Borrowed(s))
     }
 
     fn error(&mut self, err: &str) -> Self::Error {
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index 6650a981884d8..c4613c661a84b 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -14,6 +14,7 @@
 Core encoding and decoding interfaces.
 */
 
+use std::borrow::Cow;
 use std::intrinsics;
 use std::path;
 use std::rc::Rc;
@@ -156,7 +157,7 @@ pub trait Decoder {
     fn read_f64(&mut self) -> Result<f64, Self::Error>;
     fn read_f32(&mut self) -> Result<f32, Self::Error>;
     fn read_char(&mut self) -> Result<char, Self::Error>;
-    fn read_str(&mut self) -> Result<String, Self::Error>;
+    fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
 
     // Compound types:
     fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
@@ -401,7 +402,7 @@ impl Encodable for String {
 
 impl Decodable for String {
     fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
-        d.read_str()
+        Ok(d.read_str()?.into_owned())
     }
 }
 
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index fcf2d32ded960..30fc4c3dd8045 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -71,7 +71,7 @@ impl Encodable for Name {
 
 impl Decodable for Name {
     fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
-        Ok(token::intern(&d.read_str()?[..]))
+        Ok(token::intern(&d.read_str()?))
     }
 }
 
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 09bc5607946de..905886f877b56 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -566,7 +566,7 @@ impl PartialEq<InternedString> for str {
 
 impl Decodable for InternedString {
     fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(intern(d.read_str()?.as_ref()).as_str())
+        Ok(intern(d.read_str()?.deref()).as_str())
     }
 }