about summary refs log tree commit diff
path: root/compiler/rustc_serialize/src
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2022-06-07 13:30:45 +1000
committerNicholas Nethercote <n.nethercote@gmail.com>2022-06-08 07:01:26 +1000
commit1acbe7573dc32f917f51a784a36b7afc690900e3 (patch)
tree1b4e8d414de3d349bd3ae038c28e9dc77e54c345 /compiler/rustc_serialize/src
parent582b9cbc45334a73467d6ccaf0a8b9de559c2011 (diff)
downloadrust-1acbe7573dc32f917f51a784a36b7afc690900e3.tar.gz
rust-1acbe7573dc32f917f51a784a36b7afc690900e3.zip
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.

Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).

This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.

This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.

Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
  `into_inner` method is changed into `finish`, which returns
  `Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
  strategy. Its `Ok` type is a `usize`, returning the number of bytes
  written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
  passed a mutable reference, e.g. `serialize_query_result_cache`.
Diffstat (limited to 'compiler/rustc_serialize/src')
-rw-r--r--compiler/rustc_serialize/src/collection_impls.rs74
-rw-r--r--compiler/rustc_serialize/src/opaque.rs240
-rw-r--r--compiler/rustc_serialize/src/serialize.rs156
3 files changed, 246 insertions, 224 deletions
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
index c4541bbcac9..5e53f0b104d 100644
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ b/compiler/rustc_serialize/src/collection_impls.rs
@@ -10,9 +10,9 @@ use std::sync::Arc;
 use smallvec::{Array, SmallVec};
 
 impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[A::Item] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -24,12 +24,11 @@ impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_usize(self.len())?;
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?;
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
@@ -41,12 +40,11 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_usize(self.len())?;
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?;
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
@@ -62,13 +60,12 @@ where
     K: Encodable<S> + PartialEq + Ord,
     V: Encodable<S>,
 {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        e.emit_usize(self.len())?;
+    fn encode(&self, e: &mut S) {
+        e.emit_usize(self.len());
         for (key, val) in self.iter() {
-            key.encode(e)?;
-            val.encode(e)?;
+            key.encode(e);
+            val.encode(e);
         }
-        Ok(())
     }
 }
 
@@ -93,12 +90,11 @@ impl<S: Encoder, T> Encodable<S> for BTreeSet<T>
 where
     T: Encodable<S> + PartialEq + Ord,
 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_usize(self.len())?;
+    fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?;
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
@@ -122,13 +118,12 @@ where
     V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_usize(self.len())?;
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
         for (key, val) in self.iter() {
-            key.encode(e)?;
-            val.encode(e)?;
+            key.encode(e);
+            val.encode(e);
         }
-        Ok(())
     }
 }
 
@@ -156,12 +151,11 @@ where
     T: Encodable<E> + Eq,
     S: BuildHasher,
 {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_usize(self.len())?;
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?;
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
@@ -187,13 +181,12 @@ where
     V: Encodable<E>,
     S: BuildHasher,
 {
-    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
-        e.emit_usize(self.len())?;
+    fn encode(&self, e: &mut E) {
+        e.emit_usize(self.len());
         for (key, val) in self.iter() {
-            key.encode(e)?;
-            val.encode(e)?;
+            key.encode(e);
+            val.encode(e);
         }
-        Ok(())
     }
 }
 
@@ -221,12 +214,11 @@ where
     T: Encodable<E> + Hash + Eq,
     S: BuildHasher,
 {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
-        s.emit_usize(self.len())?;
+    fn encode(&self, s: &mut E) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?;
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
@@ -247,9 +239,9 @@ where
 }
 
 impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, s: &mut E) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -261,9 +253,9 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
 }
 
 impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
-    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+    fn encode(&self, s: &mut E) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 40b79ba89ef..b2dbf937eb7 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -11,8 +11,6 @@ use std::ptr;
 // Encoder
 // -----------------------------------------------------------------------------
 
-pub type EncodeResult = Result<(), !>;
-
 pub struct Encoder {
     pub data: Vec<u8>,
 }
@@ -22,10 +20,6 @@ impl Encoder {
         Encoder { data: vec![] }
     }
 
-    pub fn into_inner(self) -> Vec<u8> {
-        self.data
-    }
-
     #[inline]
     pub fn position(&self) -> usize {
         self.data.len()
@@ -49,8 +43,6 @@ macro_rules! write_leb128 {
             let encoded = leb128::$fun(buf, $value);
             $enc.data.set_len(old_len + encoded.len());
         }
-
-        Ok(())
     }};
 }
 
@@ -62,108 +54,109 @@ macro_rules! write_leb128 {
 const STR_SENTINEL: u8 = 0xC1;
 
 impl serialize::Encoder for Encoder {
-    type Error = !;
+    type Ok = Vec<u8>;
+    type Err = !;
 
     #[inline]
-    fn emit_usize(&mut self, v: usize) -> EncodeResult {
+    fn emit_usize(&mut self, v: usize) {
         write_leb128!(self, v, usize, write_usize_leb128)
     }
 
     #[inline]
-    fn emit_u128(&mut self, v: u128) -> EncodeResult {
-        write_leb128!(self, v, u128, write_u128_leb128)
+    fn emit_u128(&mut self, v: u128) {
+        write_leb128!(self, v, u128, write_u128_leb128);
     }
 
     #[inline]
-    fn emit_u64(&mut self, v: u64) -> EncodeResult {
-        write_leb128!(self, v, u64, write_u64_leb128)
+    fn emit_u64(&mut self, v: u64) {
+        write_leb128!(self, v, u64, write_u64_leb128);
     }
 
     #[inline]
-    fn emit_u32(&mut self, v: u32) -> EncodeResult {
-        write_leb128!(self, v, u32, write_u32_leb128)
+    fn emit_u32(&mut self, v: u32) {
+        write_leb128!(self, v, u32, write_u32_leb128);
     }
 
     #[inline]
-    fn emit_u16(&mut self, v: u16) -> EncodeResult {
+    fn emit_u16(&mut self, v: u16) {
         self.data.extend_from_slice(&v.to_le_bytes());
-        Ok(())
     }
 
     #[inline]
-    fn emit_u8(&mut self, v: u8) -> EncodeResult {
+    fn emit_u8(&mut self, v: u8) {
         self.data.push(v);
-        Ok(())
     }
 
     #[inline]
-    fn emit_isize(&mut self, v: isize) -> EncodeResult {
+    fn emit_isize(&mut self, v: isize) {
         write_leb128!(self, v, isize, write_isize_leb128)
     }
 
     #[inline]
-    fn emit_i128(&mut self, v: i128) -> EncodeResult {
+    fn emit_i128(&mut self, v: i128) {
         write_leb128!(self, v, i128, write_i128_leb128)
     }
 
     #[inline]
-    fn emit_i64(&mut self, v: i64) -> EncodeResult {
+    fn emit_i64(&mut self, v: i64) {
         write_leb128!(self, v, i64, write_i64_leb128)
     }
 
     #[inline]
-    fn emit_i32(&mut self, v: i32) -> EncodeResult {
+    fn emit_i32(&mut self, v: i32) {
         write_leb128!(self, v, i32, write_i32_leb128)
     }
 
     #[inline]
-    fn emit_i16(&mut self, v: i16) -> EncodeResult {
+    fn emit_i16(&mut self, v: i16) {
         self.data.extend_from_slice(&v.to_le_bytes());
-        Ok(())
     }
 
     #[inline]
-    fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        self.emit_u8(v as u8)
+    fn emit_i8(&mut self, v: i8) {
+        self.emit_u8(v as u8);
     }
 
     #[inline]
-    fn emit_bool(&mut self, v: bool) -> EncodeResult {
-        self.emit_u8(if v { 1 } else { 0 })
+    fn emit_bool(&mut self, v: bool) {
+        self.emit_u8(if v { 1 } else { 0 });
     }
 
     #[inline]
-    fn emit_f64(&mut self, v: f64) -> EncodeResult {
+    fn emit_f64(&mut self, v: f64) {
         let as_u64: u64 = v.to_bits();
-        self.emit_u64(as_u64)
+        self.emit_u64(as_u64);
     }
 
     #[inline]
-    fn emit_f32(&mut self, v: f32) -> EncodeResult {
+    fn emit_f32(&mut self, v: f32) {
         let as_u32: u32 = v.to_bits();
-        self.emit_u32(as_u32)
+        self.emit_u32(as_u32);
     }
 
     #[inline]
-    fn emit_char(&mut self, v: char) -> EncodeResult {
-        self.emit_u32(v as u32)
+    fn emit_char(&mut self, v: char) {
+        self.emit_u32(v as u32);
     }
 
     #[inline]
-    fn emit_str(&mut self, v: &str) -> EncodeResult {
-        self.emit_usize(v.len())?;
-        self.emit_raw_bytes(v.as_bytes())?;
-        self.emit_u8(STR_SENTINEL)
+    fn emit_str(&mut self, v: &str) {
+        self.emit_usize(v.len());
+        self.emit_raw_bytes(v.as_bytes());
+        self.emit_u8(STR_SENTINEL);
     }
 
     #[inline]
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> EncodeResult {
+    fn emit_raw_bytes(&mut self, s: &[u8]) {
         self.data.extend_from_slice(s);
-        Ok(())
+    }
+
+    fn finish(self) -> Result<Self::Ok, Self::Err> {
+        Ok(self.data)
     }
 }
 
-pub type FileEncodeResult = Result<(), io::Error>;
+pub type FileEncodeResult = Result<usize, io::Error>;
 
 // `FileEncoder` encodes data to file via fixed-size buffer.
 //
@@ -182,6 +175,9 @@ pub struct FileEncoder {
     buffered: usize,
     flushed: usize,
     file: File,
+    // This is used to implement delayed error handling, as described in the
+    // comment on `trait Encoder`.
+    res: Result<(), io::Error>,
 }
 
 impl FileEncoder {
@@ -202,7 +198,13 @@ impl FileEncoder {
 
         let file = File::create(path)?;
 
-        Ok(FileEncoder { buf: Box::new_uninit_slice(capacity), buffered: 0, flushed: 0, file })
+        Ok(FileEncoder {
+            buf: Box::new_uninit_slice(capacity),
+            buffered: 0,
+            flushed: 0,
+            file,
+            res: Ok(()),
+        })
     }
 
     #[inline]
@@ -212,7 +214,7 @@ impl FileEncoder {
         self.flushed + self.buffered
     }
 
-    pub fn flush(&mut self) -> FileEncodeResult {
+    pub fn flush(&mut self) {
         // This is basically a copy of `BufWriter::flush`. If `BufWriter` ever
         // offers a raw buffer access API, we can use it, and remove this.
 
@@ -267,6 +269,12 @@ impl FileEncoder {
             }
         }
 
+        // If we've already had an error, do nothing. It'll get reported after
+        // `finish` is called.
+        if self.res.is_err() {
+            return;
+        }
+
         let mut guard = BufGuard::new(
             unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[..self.buffered]) },
             &mut self.buffered,
@@ -276,18 +284,20 @@ impl FileEncoder {
         while !guard.done() {
             match self.file.write(guard.remaining()) {
                 Ok(0) => {
-                    return Err(io::Error::new(
+                    self.res = Err(io::Error::new(
                         io::ErrorKind::WriteZero,
                         "failed to write the buffered data",
                     ));
+                    return;
                 }
                 Ok(n) => guard.consume(n),
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
+                Err(e) => {
+                    self.res = Err(e);
+                    return;
+                }
             }
         }
-
-        Ok(())
     }
 
     #[inline]
@@ -296,14 +306,14 @@ impl FileEncoder {
     }
 
     #[inline]
-    fn write_one(&mut self, value: u8) -> FileEncodeResult {
+    fn write_one(&mut self, value: u8) {
         // We ensure this during `FileEncoder` construction.
         debug_assert!(self.capacity() >= 1);
 
         let mut buffered = self.buffered;
 
         if std::intrinsics::unlikely(buffered >= self.capacity()) {
-            self.flush()?;
+            self.flush();
             buffered = 0;
         }
 
@@ -314,12 +324,10 @@ impl FileEncoder {
         }
 
         self.buffered = buffered + 1;
-
-        Ok(())
     }
 
     #[inline]
-    fn write_all(&mut self, buf: &[u8]) -> FileEncodeResult {
+    fn write_all(&mut self, buf: &[u8]) {
         let capacity = self.capacity();
         let buf_len = buf.len();
 
@@ -327,7 +335,7 @@ impl FileEncoder {
             let mut buffered = self.buffered;
 
             if std::intrinsics::unlikely(buf_len > capacity - buffered) {
-                self.flush()?;
+                self.flush();
                 buffered = 0;
             }
 
@@ -340,16 +348,20 @@ impl FileEncoder {
             }
 
             self.buffered = buffered + buf_len;
-
-            Ok(())
         } else {
-            self.write_all_unbuffered(buf)
+            self.write_all_unbuffered(buf);
         }
     }
 
-    fn write_all_unbuffered(&mut self, mut buf: &[u8]) -> FileEncodeResult {
+    fn write_all_unbuffered(&mut self, mut buf: &[u8]) {
+        // If we've already had an error, do nothing. It'll get reported after
+        // `finish` is called.
+        if self.res.is_err() {
+            return;
+        }
+
         if self.buffered > 0 {
-            self.flush()?;
+            self.flush();
         }
 
         // This is basically a copy of `Write::write_all` but also updates our
@@ -359,26 +371,30 @@ impl FileEncoder {
         while !buf.is_empty() {
             match self.file.write(buf) {
                 Ok(0) => {
-                    return Err(io::Error::new(
+                    self.res = Err(io::Error::new(
                         io::ErrorKind::WriteZero,
                         "failed to write whole buffer",
                     ));
+                    return;
                 }
                 Ok(n) => {
                     buf = &buf[n..];
                     self.flushed += n;
                 }
                 Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
+                Err(e) => {
+                    self.res = Err(e);
+                    return;
+                }
             }
         }
-
-        Ok(())
     }
 }
 
 impl Drop for FileEncoder {
     fn drop(&mut self) {
+        // Likely to be a no-op, because `finish` should have been called and
+        // it also flushes. But do it just in case.
         let _result = self.flush();
     }
 }
@@ -394,7 +410,7 @@ macro_rules! file_encoder_write_leb128 {
 
         // This can't overflow. See assertion in `FileEncoder::with_capacity`.
         if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
-            $enc.flush()?;
+            $enc.flush();
             buffered = 0;
         }
 
@@ -406,106 +422,112 @@ macro_rules! file_encoder_write_leb128 {
 
         let encoded = leb128::$fun(buf, $value);
         $enc.buffered = buffered + encoded.len();
-
-        Ok(())
     }};
 }
 
 impl serialize::Encoder for FileEncoder {
-    type Error = io::Error;
+    type Ok = usize;
+    type Err = io::Error;
 
     #[inline]
-    fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
+    fn emit_usize(&mut self, v: usize) {
         file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
     }
 
     #[inline]
-    fn emit_u128(&mut self, v: u128) -> FileEncodeResult {
+    fn emit_u128(&mut self, v: u128) {
         file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
     }
 
     #[inline]
-    fn emit_u64(&mut self, v: u64) -> FileEncodeResult {
+    fn emit_u64(&mut self, v: u64) {
         file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
     }
 
     #[inline]
-    fn emit_u32(&mut self, v: u32) -> FileEncodeResult {
+    fn emit_u32(&mut self, v: u32) {
         file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
     }
 
     #[inline]
-    fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
-        self.write_all(&v.to_le_bytes())
+    fn emit_u16(&mut self, v: u16) {
+        self.write_all(&v.to_le_bytes());
     }
 
     #[inline]
-    fn emit_u8(&mut self, v: u8) -> FileEncodeResult {
-        self.write_one(v)
+    fn emit_u8(&mut self, v: u8) {
+        self.write_one(v);
     }
 
     #[inline]
-    fn emit_isize(&mut self, v: isize) -> FileEncodeResult {
+    fn emit_isize(&mut self, v: isize) {
         file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
     }
 
     #[inline]
-    fn emit_i128(&mut self, v: i128) -> FileEncodeResult {
+    fn emit_i128(&mut self, v: i128) {
         file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
     }
 
     #[inline]
-    fn emit_i64(&mut self, v: i64) -> FileEncodeResult {
+    fn emit_i64(&mut self, v: i64) {
         file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
     }
 
     #[inline]
-    fn emit_i32(&mut self, v: i32) -> FileEncodeResult {
+    fn emit_i32(&mut self, v: i32) {
         file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
     }
 
     #[inline]
-    fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
-        self.write_all(&v.to_le_bytes())
+    fn emit_i16(&mut self, v: i16) {
+        self.write_all(&v.to_le_bytes());
     }
 
     #[inline]
-    fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
-        self.emit_u8(v as u8)
+    fn emit_i8(&mut self, v: i8) {
+        self.emit_u8(v as u8);
     }
 
     #[inline]
-    fn emit_bool(&mut self, v: bool) -> FileEncodeResult {
-        self.emit_u8(if v { 1 } else { 0 })
+    fn emit_bool(&mut self, v: bool) {
+        self.emit_u8(if v { 1 } else { 0 });
     }
 
     #[inline]
-    fn emit_f64(&mut self, v: f64) -> FileEncodeResult {
+    fn emit_f64(&mut self, v: f64) {
         let as_u64: u64 = v.to_bits();
-        self.emit_u64(as_u64)
+        self.emit_u64(as_u64);
     }
 
     #[inline]
-    fn emit_f32(&mut self, v: f32) -> FileEncodeResult {
+    fn emit_f32(&mut self, v: f32) {
         let as_u32: u32 = v.to_bits();
-        self.emit_u32(as_u32)
+        self.emit_u32(as_u32);
     }
 
     #[inline]
-    fn emit_char(&mut self, v: char) -> FileEncodeResult {
-        self.emit_u32(v as u32)
+    fn emit_char(&mut self, v: char) {
+        self.emit_u32(v as u32);
     }
 
     #[inline]
-    fn emit_str(&mut self, v: &str) -> FileEncodeResult {
-        self.emit_usize(v.len())?;
-        self.emit_raw_bytes(v.as_bytes())?;
-        self.emit_u8(STR_SENTINEL)
+    fn emit_str(&mut self, v: &str) {
+        self.emit_usize(v.len());
+        self.emit_raw_bytes(v.as_bytes());
+        self.emit_u8(STR_SENTINEL);
     }
 
     #[inline]
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> FileEncodeResult {
-        self.write_all(s)
+    fn emit_raw_bytes(&mut self, s: &[u8]) {
+        self.write_all(s);
+    }
+
+    fn finish(mut self) -> Result<usize, io::Error> {
+        self.flush();
+
+        let res = std::mem::replace(&mut self.res, Ok(()));
+        res.map(|()| self.position())
     }
 }
 
@@ -667,16 +689,16 @@ impl<'a> serialize::Decoder for Decoder<'a> {
 // Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
 // since the default implementations call `encode` on their slices internally.
 impl serialize::Encodable<Encoder> for [u8] {
-    fn encode(&self, e: &mut Encoder) -> EncodeResult {
-        serialize::Encoder::emit_usize(e, self.len())?;
-        e.emit_raw_bytes(self)
+    fn encode(&self, e: &mut Encoder) {
+        serialize::Encoder::emit_usize(e, self.len());
+        e.emit_raw_bytes(self);
     }
 }
 
 impl serialize::Encodable<FileEncoder> for [u8] {
-    fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
-        serialize::Encoder::emit_usize(e, self.len())?;
-        e.emit_raw_bytes(self)
+    fn encode(&self, e: &mut FileEncoder) {
+        serialize::Encoder::emit_usize(e, self.len());
+        e.emit_raw_bytes(self);
     }
 }
 
@@ -698,23 +720,21 @@ impl IntEncodedWithFixedSize {
 
 impl serialize::Encodable<Encoder> for IntEncodedWithFixedSize {
     #[inline]
-    fn encode(&self, e: &mut Encoder) -> EncodeResult {
+    fn encode(&self, e: &mut Encoder) {
         let _start_pos = e.position();
-        e.emit_raw_bytes(&self.0.to_le_bytes())?;
+        e.emit_raw_bytes(&self.0.to_le_bytes());
         let _end_pos = e.position();
         debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
-        Ok(())
     }
 }
 
 impl serialize::Encodable<FileEncoder> for IntEncodedWithFixedSize {
     #[inline]
-    fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
+    fn encode(&self, e: &mut FileEncoder) {
         let _start_pos = e.position();
-        e.emit_raw_bytes(&self.0.to_le_bytes())?;
+        e.emit_raw_bytes(&self.0.to_le_bytes());
         let _end_pos = e.position();
         debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
-        Ok(())
     }
 }
 
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 817a0c9dcb1..98bb18581f5 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -11,36 +11,47 @@ use std::path;
 use std::rc::Rc;
 use std::sync::Arc;
 
+/// A note about error handling.
+///
+/// Encoders may be fallible, but in practice failure is rare and there are so
+/// many nested calls that typical Rust error handling (via `Result` and `?`)
+/// is pervasive and has non-trivial cost. Instead, impls of this trait must
+/// implement a delayed error handling strategy. If a failure occurs, they
+/// should record this internally, and all subsequent encoding operations can
+/// be processed or ignored, whichever is appropriate. Then when `finish()` is
+/// called, an error result should be returned to indicate the failure. If no
+/// failures occurred, then `finish()` should return a success result.
 pub trait Encoder {
-    type Error;
+    type Ok;
+    type Err;
 
     // Primitive types:
-    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>;
-    fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>;
-    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>;
-    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>;
-    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>;
-    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>;
-    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>;
-    fn emit_i128(&mut self, v: i128) -> Result<(), Self::Error>;
-    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>;
-    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>;
-    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>;
-    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error>;
-    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error>;
-    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error>;
-    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error>;
-    fn emit_char(&mut self, v: char) -> Result<(), Self::Error>;
-    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>;
-    fn emit_raw_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error>;
+    fn emit_usize(&mut self, v: usize);
+    fn emit_u128(&mut self, v: u128);
+    fn emit_u64(&mut self, v: u64);
+    fn emit_u32(&mut self, v: u32);
+    fn emit_u16(&mut self, v: u16);
+    fn emit_u8(&mut self, v: u8);
+    fn emit_isize(&mut self, v: isize);
+    fn emit_i128(&mut self, v: i128);
+    fn emit_i64(&mut self, v: i64);
+    fn emit_i32(&mut self, v: i32);
+    fn emit_i16(&mut self, v: i16);
+    fn emit_i8(&mut self, v: i8);
+    fn emit_bool(&mut self, v: bool);
+    fn emit_f64(&mut self, v: f64);
+    fn emit_f32(&mut self, v: f32);
+    fn emit_char(&mut self, v: char);
+    fn emit_str(&mut self, v: &str);
+    fn emit_raw_bytes(&mut self, s: &[u8]);
 
     // Convenience for the derive macro:
-    fn emit_enum_variant<F>(&mut self, v_id: usize, f: F) -> Result<(), Self::Error>
+    fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
     where
-        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
+        F: FnOnce(&mut Self),
     {
-        self.emit_usize(v_id)?;
-        f(self)
+        self.emit_usize(v_id);
+        f(self);
     }
 
     // We put the field index in a const generic to allow the emit_usize to be
@@ -50,9 +61,12 @@ pub trait Encoder {
     // optimization that would otherwise be necessary here, likely due to the
     // multiple levels of inlining and const-prop that are needed.
     #[inline]
-    fn emit_fieldless_enum_variant<const ID: usize>(&mut self) -> Result<(), Self::Error> {
+    fn emit_fieldless_enum_variant<const ID: usize>(&mut self) {
         self.emit_usize(ID)
     }
+
+    // Consume the encoder, getting the result.
+    fn finish(self) -> Result<Self::Ok, Self::Err>;
 }
 
 // Note: all the methods in this trait are infallible, which may be surprising.
@@ -95,7 +109,7 @@ pub trait Decoder {
 /// * `TyEncodable` should be used for types that are only serialized in crate
 ///   metadata or the incremental cache. This is most types in `rustc_middle`.
 pub trait Encodable<S: Encoder> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error>;
+    fn encode(&self, s: &mut S);
 }
 
 /// Trait for types that can be deserialized
@@ -117,8 +131,8 @@ macro_rules! direct_serialize_impls {
     ($($ty:ident $emit_method:ident $read_method:ident),*) => {
         $(
             impl<S: Encoder> Encodable<S> for $ty {
-                fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-                    s.$emit_method(*self)
+                fn encode(&self, s: &mut S) {
+                    s.$emit_method(*self);
                 }
             }
 
@@ -138,12 +152,14 @@ direct_serialize_impls! {
     u32 emit_u32 read_u32,
     u64 emit_u64 read_u64,
     u128 emit_u128 read_u128,
+
     isize emit_isize read_isize,
     i8 emit_i8 read_i8,
     i16 emit_i16 read_i16,
     i32 emit_i32 read_i32,
     i64 emit_i64 read_i64,
     i128 emit_i128 read_i128,
+
     f32 emit_f32 read_f32,
     f64 emit_f64 read_f64,
     bool emit_bool read_bool,
@@ -154,14 +170,14 @@ impl<S: Encoder, T: ?Sized> Encodable<S> for &T
 where
     T: Encodable<S>,
 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         (**self).encode(s)
     }
 }
 
 impl<S: Encoder> Encodable<S> for ! {
-    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
-        unreachable!()
+    fn encode(&self, _s: &mut S) {
+        unreachable!();
     }
 }
 
@@ -172,8 +188,8 @@ impl<D: Decoder> Decodable<D> for ! {
 }
 
 impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_u32(self.get())
+    fn encode(&self, s: &mut S) {
+        s.emit_u32(self.get());
     }
 }
 
@@ -184,14 +200,14 @@ impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 {
 }
 
 impl<S: Encoder> Encodable<S> for str {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(self)
+    fn encode(&self, s: &mut S) {
+        s.emit_str(self);
     }
 }
 
 impl<S: Encoder> Encodable<S> for String {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_str(&self[..])
+    fn encode(&self, s: &mut S) {
+        s.emit_str(&self[..]);
     }
 }
 
@@ -202,9 +218,7 @@ impl<D: Decoder> Decodable<D> for String {
 }
 
 impl<S: Encoder> Encodable<S> for () {
-    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
-        Ok(())
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
 impl<D: Decoder> Decodable<D> for () {
@@ -212,9 +226,7 @@ impl<D: Decoder> Decodable<D> for () {
 }
 
 impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
-    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
-        Ok(())
-    }
+    fn encode(&self, _s: &mut S) {}
 }
 
 impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
@@ -231,8 +243,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Rc<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
@@ -243,19 +255,18 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<T> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
-    default fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        s.emit_usize(self.len())?;
+    default fn encode(&self, s: &mut S) {
+        s.emit_usize(self.len());
         for e in self.iter() {
-            e.encode(s)?
+            e.encode(s);
         }
-        Ok(())
     }
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -277,9 +288,9 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
 }
 
 impl<S: Encoder, T: Encodable<S>, const N: usize> Encodable<S> for [T; N] {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -299,9 +310,9 @@ impl<'a, S: Encoder, T: Encodable<S>> Encodable<S> for Cow<'a, [T]>
 where
     [T]: ToOwned<Owned = Vec<T>>,
 {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let slice: &[T] = self;
-        slice.encode(s)
+        slice.encode(s);
     }
 }
 
@@ -316,7 +327,7 @@ where
 }
 
 impl<'a, S: Encoder> Encodable<S> for Cow<'a, str> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         let val: &str = self;
         val.encode(s)
     }
@@ -330,9 +341,9 @@ impl<'a, D: Decoder> Decodable<D> for Cow<'a, str> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         match *self {
-            None => s.emit_enum_variant(0, |_| Ok(())),
+            None => s.emit_enum_variant(0, |_| {}),
             Some(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
         }
     }
@@ -349,7 +360,7 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
 }
 
 impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1, T2> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+    fn encode(&self, s: &mut S) {
         match *self {
             Ok(ref v) => s.emit_enum_variant(0, |s| v.encode(s)),
             Err(ref v) => s.emit_enum_variant(1, |s| v.encode(s)),
@@ -381,10 +392,9 @@ macro_rules! tuple {
         }
         impl<S: Encoder, $($name: Encodable<S>),+> Encodable<S> for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+            fn encode(&self, s: &mut S) {
                 let ($(ref $name,)+) = *self;
-                $($name.encode(s)?;)+
-                Ok(())
+                $($name.encode(s);)+
             }
         }
         peel! { $($name,)+ }
@@ -394,14 +404,14 @@ macro_rules! tuple {
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
 impl<S: Encoder> Encodable<S> for path::Path {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        self.to_str().unwrap().encode(e)
+    fn encode(&self, e: &mut S) {
+        self.to_str().unwrap().encode(e);
     }
 }
 
 impl<S: Encoder> Encodable<S> for path::PathBuf {
-    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
-        path::Path::encode(self, e)
+    fn encode(&self, e: &mut S) {
+        path::Path::encode(self, e);
     }
 }
 
@@ -413,8 +423,8 @@ impl<D: Decoder> Decodable<D> for path::PathBuf {
 }
 
 impl<S: Encoder, T: Encodable<S> + Copy> Encodable<S> for Cell<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        self.get().encode(s)
+    fn encode(&self, s: &mut S) {
+        self.get().encode(s);
     }
 }
 
@@ -430,8 +440,8 @@ impl<D: Decoder, T: Decodable<D> + Copy> Decodable<D> for Cell<T> {
 // from `encode` when `try_borrow` returns `None`.
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for RefCell<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        self.borrow().encode(s)
+    fn encode(&self, s: &mut S) {
+        self.borrow().encode(s);
     }
 }
 
@@ -442,8 +452,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for RefCell<T> {
 }
 
 impl<S: Encoder, T: Encodable<S>> Encodable<S> for Arc<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 
@@ -454,8 +464,8 @@ impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> {
 }
 
 impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> {
-    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        (**self).encode(s)
+    fn encode(&self, s: &mut S) {
+        (**self).encode(s);
     }
 }
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {