about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <17426603+bjorn3@users.noreply.github.com>2023-12-31 19:35:32 +0000
committerbjorn3 <17426603+bjorn3@users.noreply.github.com>2023-12-31 20:42:17 +0000
commit6ed37bdc4260bdf64acf0cb2c728d6724c94ac3d (patch)
tree3df832c93a180eeac81b2705954c0fb3c59ccef1
parent1c204623386a86d5d6391111b42fc06686374c85 (diff)
Avoid specialization for the Span Encodable and Decodable impls
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_abi/src/lib.rs14
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs8
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs2
-rw-r--r--compiler/rustc_data_structures/src/svh.rs2
-rw-r--r--compiler/rustc_data_structures/src/unord.rs6
-rw-r--r--compiler/rustc_index/src/bit_set.rs8
-rw-r--r--compiler/rustc_macros/src/lib.rs2
-rw-r--r--compiler/rustc_macros/src/serialize.rs16
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs18
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs22
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs65
-rw-r--r--compiler/rustc_serialize/tests/opaque.rs16
-rw-r--r--compiler/rustc_span/src/lib.rs46
-rw-r--r--compiler/rustc_type_ir/Cargo.toml2
-rw-r--r--compiler/rustc_type_ir/src/codec.rs6
16 files changed, 140 insertions, 94 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b8192e333fe..1948e6c2e5e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4644,6 +4644,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_serialize",
+ "rustc_span",
  "smallvec",
 ]
 
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 549927d5898..ea194e10def 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::stable_hasher::StableOrd;
 #[cfg(feature = "nightly")]
 use rustc_macros::HashStable_Generic;
 #[cfg(feature = "nightly")]
-use rustc_macros::{Decodable, Encodable};
+use rustc_macros::{Decodable_Generic, Encodable_Generic};
 #[cfg(feature = "nightly")]
 use std::iter::Step;
 
@@ -30,7 +30,7 @@ pub use layout::LayoutCalculator;
 pub trait HashStableContext {}
 
 #[derive(Clone, Copy, PartialEq, Eq, Default)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub struct ReprFlags(u8);
 
 bitflags! {
@@ -52,7 +52,7 @@ bitflags! {
 rustc_data_structures::external_bitflags_debug! { ReprFlags }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub enum IntegerType {
     /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g.
     /// `Pointer(true)` means `isize`.
@@ -73,7 +73,7 @@ impl IntegerType {
 
 /// Represents the repr options provided by the user.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub struct ReprOptions {
     pub int: Option<IntegerType>,
     pub align: Option<Align>,
@@ -412,7 +412,7 @@ impl FromStr for Endian {
 
 /// Size of a type in bytes.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub struct Size {
     raw: u64,
 }
@@ -636,7 +636,7 @@ impl Step for Size {
 
 /// Alignment of a type in bytes (always a power of two).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub struct Align {
     pow2: u8,
 }
@@ -777,7 +777,7 @@ impl AbiAndPrefAlign {
 
 /// Integers, also used for enum discriminants.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_Generic))]
+#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))]
 pub enum Integer {
     I8,
     I16,
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 4c0c496584e..503862e6f01 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -21,8 +21,8 @@ use crate::AttrVec;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_macros::HashStable_Generic;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_serialize::{Decodable, Encodable};
+use rustc_span::{sym, Span, SpanDecoder, SpanEncoder, Symbol, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
@@ -158,14 +158,14 @@ impl fmt::Debug for LazyAttrTokenStream {
     }
 }
 
-impl<S: Encoder> Encodable<S> for LazyAttrTokenStream {
+impl<S: SpanEncoder> Encodable<S> for LazyAttrTokenStream {
     fn encode(&self, s: &mut S) {
         // Used by AST json printing.
         Encodable::encode(&self.to_attr_token_stream(), s);
     }
 }
 
-impl<D: Decoder> Decodable<D> for LazyAttrTokenStream {
+impl<D: SpanDecoder> Decodable<D> for LazyAttrTokenStream {
     fn decode(_d: &mut D) -> Self {
         panic!("Attempted to decode LazyAttrTokenStream");
     }
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index ed2e558bffa..1436628139f 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -16,7 +16,7 @@ pub use index_map::SortedIndexMultiMap;
 /// stores data in a more compact way. It also supports accessing contiguous
 /// ranges of elements as a slice, and slices of already sorted elements can be
 /// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_Generic, Decodable_Generic)]
 pub struct SortedMap<K, V> {
     data: Vec<(K, V)>,
 }
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index 71679086f16..1cfc9fecd47 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -10,7 +10,7 @@ use std::fmt;
 
 use crate::stable_hasher;
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)]
 pub struct Svh {
     hash: Fingerprint,
 }
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index 47c56eba7ad..9f8ddbd4256 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -185,7 +185,7 @@ trait UnordCollection {}
 ///
 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
 /// for more information.
-#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)]
 pub struct UnordSet<V: Eq + Hash> {
     inner: FxHashSet<V>,
 }
@@ -362,7 +362,7 @@ impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
 ///
 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
 /// for more information.
-#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)]
 pub struct UnordMap<K: Eq + Hash, V> {
     inner: FxHashMap<K, V>,
 }
@@ -558,7 +558,7 @@ impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> fo
 ///
 /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
 /// for more information.
-#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)]
 pub struct UnordBag<V> {
     inner: Vec<V>,
 }
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index d730ef58deb..cba02548eb5 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -10,7 +10,7 @@ use arrayvec::ArrayVec;
 use smallvec::{smallvec, SmallVec};
 
 #[cfg(feature = "nightly")]
-use rustc_macros::{Decodable, Encodable};
+use rustc_macros::{Decodable_Generic, Encodable_Generic};
 
 use crate::{Idx, IndexVec};
 
@@ -112,7 +112,7 @@ macro_rules! bit_relations_inherent_impls {
 /// to or greater than the domain size. All operations that involve two bitsets
 /// will panic if the bitsets have differing domain sizes.
 ///
-#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))]
 #[derive(Eq, PartialEq, Hash)]
 pub struct BitSet<T> {
     domain_size: usize,
@@ -1590,7 +1590,7 @@ impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> {
 ///
 /// All operations that involve a row and/or column index will panic if the
 /// index exceeds the relevant bound.
-#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))]
 #[derive(Clone, Eq, PartialEq, Hash)]
 pub struct BitMatrix<R: Idx, C: Idx> {
     num_rows: usize,
@@ -2020,7 +2020,7 @@ impl std::fmt::Debug for FiniteBitSet<u32> {
 
 /// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
 /// representable by `T` are considered set.
-#[cfg_attr(feature = "nightly", derive(Decodable, Encodable))]
+#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))]
 #[derive(Copy, Clone, Eq, PartialEq)]
 pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
 
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index f558b74be9a..f5d942b924e 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -56,6 +56,8 @@ decl_derive!(
     hash_stable::hash_stable_no_context_derive
 );
 
+decl_derive!([Decodable_Generic] => serialize::decodable_generic_derive);
+decl_derive!([Encodable_Generic] => serialize::encodable_generic_derive);
 decl_derive!([Decodable] => serialize::decodable_derive);
 decl_derive!([Encodable] => serialize::encodable_derive);
 decl_derive!([TyDecodable] => serialize::type_decodable_derive);
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 047066ac681..9ca7ce09ba6 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -32,6 +32,14 @@ pub fn meta_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
 
 pub fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     let decoder_ty = quote! { __D };
+    s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_span::SpanDecoder});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    decodable_body(s, decoder_ty)
+}
+
+pub fn decodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let decoder_ty = quote! { __D };
     s.add_impl_generic(parse_quote! {#decoder_ty: ::rustc_serialize::Decoder});
     s.add_bounds(synstructure::AddBounds::Generics);
 
@@ -130,6 +138,14 @@ pub fn meta_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2:
 
 pub fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     let encoder_ty = quote! { __E };
+    s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder});
+    s.add_bounds(synstructure::AddBounds::Generics);
+
+    encodable_body(s, encoder_ty, false)
+}
+
+pub fn encodable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let encoder_ty = quote! { __E };
     s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder});
     s.add_bounds(synstructure::AddBounds::Generics);
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2de29db9e5c..2dffd5446a3 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -26,7 +26,7 @@ use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{CrateSource, ExternCrate};
 use rustc_session::Session;
 use rustc_span::symbol::kw;
-use rustc_span::{BytePos, Pos, SpanData, SyntaxContext, DUMMY_SP};
+use rustc_span::{BytePos, Pos, SpanData, SpanDecoder, SyntaxContext, DUMMY_SP};
 
 use proc_macro::bridge::client::ProcMacro;
 use std::iter::TrustedLen;
@@ -505,22 +505,22 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
-        let start = decoder.position();
-        let tag = SpanTag(decoder.peek_byte());
+impl<'a, 'tcx> SpanDecoder for DecodeContext<'a, 'tcx> {
+    fn decode_span(&mut self) -> Span {
+        let start = self.position();
+        let tag = SpanTag(self.peek_byte());
         let data = if tag.kind() == SpanKind::Indirect {
             // Skip past the tag we just peek'd.
-            decoder.read_u8();
-            let offset_or_position = decoder.read_usize();
+            self.read_u8();
+            let offset_or_position = self.read_usize();
             let position = if tag.is_relative_offset() {
                 start - offset_or_position
             } else {
                 offset_or_position
             };
-            decoder.with_position(position, SpanData::decode)
+            self.with_position(position, SpanData::decode)
         } else {
-            SpanData::decode(decoder)
+            SpanData::decode(self)
         };
         Span::new(data.lo, data.hi, data.ctxt, data.parent)
     }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index aca7a66596e..dbd82d3ab79 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -27,7 +27,7 @@ use rustc_session::config::{CrateType, OptLevel};
 use rustc_span::hygiene::HygieneEncodeContext;
 use rustc_span::symbol::sym;
 use rustc_span::{
-    ExternalSource, FileName, SourceFile, SpanData, StableSourceFileId, SyntaxContext,
+    ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext,
 };
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
@@ -166,29 +166,29 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
     }
 }
 
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
-    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
-        match s.span_shorthands.entry(*self) {
+impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> {
+    fn encode_span(&mut self, span: Span) {
+        match self.span_shorthands.entry(span) {
             Entry::Occupied(o) => {
                 // If an offset is smaller than the absolute position, we encode with the offset.
                 // This saves space since smaller numbers encode in less bits.
                 let last_location = *o.get();
                 // This cannot underflow. Metadata is written with increasing position(), so any
                 // previously saved offset must be smaller than the current position.
-                let offset = s.opaque.position() - last_location;
+                let offset = self.opaque.position() - last_location;
                 if offset < last_location {
-                    SpanTag::indirect(true).encode(s);
-                    offset.encode(s);
+                    SpanTag::indirect(true).encode(self);
+                    offset.encode(self);
                 } else {
-                    SpanTag::indirect(false).encode(s);
-                    last_location.encode(s);
+                    SpanTag::indirect(false).encode(self);
+                    last_location.encode(self);
                 }
             }
             Entry::Vacant(v) => {
-                let position = s.opaque.position();
+                let position = self.opaque.position();
                 v.insert(position);
                 // Data is encoded with a SpanTag prefix (see below).
-                self.data().encode(s);
+                span.data().encode(self);
             }
         }
     }
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 0577d22d850..f8a34e05eb0 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -22,7 +22,8 @@ use rustc_span::hygiene::{
 };
 use rustc_span::source_map::SourceMap;
 use rustc_span::{
-    BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, StableSourceFileId,
+    BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span, SpanDecoder, SpanEncoder,
+    StableSourceFileId,
 };
 use rustc_span::{CachingSourceMapView, Symbol};
 use std::collections::hash_map::Entry;
@@ -648,19 +649,19 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
-    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
-        let ctxt = SyntaxContext::decode(decoder);
-        let parent = Option::<LocalDefId>::decode(decoder);
-        let tag: u8 = Decodable::decode(decoder);
+impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> {
+    fn decode_span(&mut self) -> Span {
+        let ctxt = SyntaxContext::decode(self);
+        let parent = Option::<LocalDefId>::decode(self);
+        let tag: u8 = Decodable::decode(self);
 
         if tag == TAG_PARTIAL_SPAN {
             return Span::new(BytePos(0), BytePos(0), ctxt, parent);
         } else if tag == TAG_RELATIVE_SPAN {
-            let dlo = u32::decode(decoder);
-            let dto = u32::decode(decoder);
+            let dlo = u32::decode(self);
+            let dto = u32::decode(self);
 
-            let enclosing = decoder.tcx.source_span_untracked(parent.unwrap()).data_untracked();
+            let enclosing = self.tcx.source_span_untracked(parent.unwrap()).data_untracked();
             let span = Span::new(
                 enclosing.lo + BytePos::from_u32(dlo),
                 enclosing.lo + BytePos::from_u32(dto),
@@ -673,12 +674,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
             debug_assert_eq!(tag, TAG_FULL_SPAN);
         }
 
-        let file_lo_index = SourceFileIndex::decode(decoder);
-        let line_lo = usize::decode(decoder);
-        let col_lo = RelativeBytePos::decode(decoder);
-        let len = BytePos::decode(decoder);
+        let file_lo_index = SourceFileIndex::decode(self);
+        let line_lo = usize::decode(self);
+        let col_lo = RelativeBytePos::decode(self);
+        let len = BytePos::decode(self);
 
-        let file_lo = decoder.file_index_to_file(file_lo_index);
+        let file_lo = self.file_index_to_file(file_lo_index);
         let lo = file_lo.lines()[line_lo - 1] + col_lo;
         let lo = file_lo.absolute_position(lo);
         let hi = lo + len;
@@ -872,47 +873,47 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for ExpnId {
     }
 }
 
-impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for Span {
-    fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
-        let span_data = self.data_untracked();
-        span_data.ctxt.encode(s);
-        span_data.parent.encode(s);
+impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> {
+    fn encode_span(&mut self, span: Span) {
+        let span_data = span.data_untracked();
+        span_data.ctxt.encode(self);
+        span_data.parent.encode(self);
 
         if span_data.is_dummy() {
-            return TAG_PARTIAL_SPAN.encode(s);
+            return TAG_PARTIAL_SPAN.encode(self);
         }
 
         if let Some(parent) = span_data.parent {
-            let enclosing = s.tcx.source_span_untracked(parent).data_untracked();
+            let enclosing = self.tcx.source_span_untracked(parent).data_untracked();
             if enclosing.contains(span_data) {
-                TAG_RELATIVE_SPAN.encode(s);
-                (span_data.lo - enclosing.lo).to_u32().encode(s);
-                (span_data.hi - enclosing.lo).to_u32().encode(s);
+                TAG_RELATIVE_SPAN.encode(self);
+                (span_data.lo - enclosing.lo).to_u32().encode(self);
+                (span_data.hi - enclosing.lo).to_u32().encode(self);
                 return;
             }
         }
 
-        let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
+        let pos = self.source_map.byte_pos_to_line_and_col(span_data.lo);
         let partial_span = match &pos {
             Some((file_lo, _, _)) => !file_lo.contains(span_data.hi),
             None => true,
         };
 
         if partial_span {
-            return TAG_PARTIAL_SPAN.encode(s);
+            return TAG_PARTIAL_SPAN.encode(self);
         }
 
         let (file_lo, line_lo, col_lo) = pos.unwrap();
 
         let len = span_data.hi - span_data.lo;
 
-        let source_file_index = s.source_file_index(file_lo);
+        let source_file_index = self.source_file_index(file_lo);
 
-        TAG_FULL_SPAN.encode(s);
-        source_file_index.encode(s);
-        line_lo.encode(s);
-        col_lo.encode(s);
-        len.encode(s);
+        TAG_FULL_SPAN.encode(self);
+        source_file_index.encode(self);
+        line_lo.encode(self);
+        col_lo.encode(self);
+        len.encode(self);
     }
 }
 
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 861091688bb..45ff85f38d2 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -1,12 +1,12 @@
 #![allow(rustc::internal)]
 
-use rustc_macros::{Decodable, Encodable};
-use rustc_serialize::opaque::{MemDecoder, FileEncoder};
+use rustc_macros::{Decodable_Generic, Encodable_Generic};
+use rustc_serialize::opaque::{FileEncoder, MemDecoder};
 use rustc_serialize::{Decodable, Encodable};
 use std::fmt::Debug;
 use std::fs;
 
-#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)]
 struct Struct {
     a: (),
     b: u8,
@@ -209,7 +209,7 @@ fn test_struct() {
     }]);
 }
 
-#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)]
 enum Enum {
     Variant1,
     Variant2(usize, u32),
@@ -258,7 +258,7 @@ fn test_tuples() {
 
 #[test]
 fn test_unit_like_struct() {
-    #[derive(Encodable, Decodable, PartialEq, Debug)]
+    #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)]
     struct UnitLikeStruct;
 
     check_round_trip(vec![UnitLikeStruct]);
@@ -266,7 +266,7 @@ fn test_unit_like_struct() {
 
 #[test]
 fn test_box() {
-    #[derive(Encodable, Decodable, PartialEq, Debug)]
+    #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)]
     struct A {
         foo: Box<[bool]>,
     }
@@ -279,12 +279,12 @@ fn test_box() {
 fn test_cell() {
     use std::cell::{Cell, RefCell};
 
-    #[derive(Encodable, Decodable, PartialEq, Debug)]
+    #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)]
     struct A {
         baz: isize,
     }
 
-    #[derive(Encodable, Decodable, PartialEq, Debug)]
+    #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)]
     struct B {
         foo: Cell<bool>,
         bar: RefCell<A>,
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 8f64eed9a87..0eafbae6e82 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -35,6 +35,8 @@
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
+extern crate self as rustc_span;
+
 #[macro_use]
 extern crate rustc_macros;
 
@@ -43,6 +45,7 @@ extern crate tracing;
 
 use rustc_data_structures::{outline, AtomicRef};
 use rustc_macros::HashStable_Generic;
+use rustc_serialize::opaque::{FileEncoder, MemDecoder};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 
 mod caching_source_map_view;
@@ -1016,22 +1019,43 @@ impl Default for Span {
     }
 }
 
-impl<E: Encoder> Encodable<E> for Span {
-    default fn encode(&self, s: &mut E) {
-        let span = self.data();
-        span.lo.encode(s);
-        span.hi.encode(s);
+pub trait SpanEncoder: Encoder {
+    fn encode_span(&mut self, span: Span);
+}
+
+impl SpanEncoder for FileEncoder {
+    fn encode_span(&mut self, span: Span) {
+        let span = span.data();
+        span.lo.encode(self);
+        span.hi.encode(self);
+    }
+}
+
+impl<E: SpanEncoder> Encodable<E> for Span {
+    fn encode(&self, s: &mut E) {
+        s.encode_span(*self);
     }
 }
-impl<D: Decoder> Decodable<D> for Span {
-    default fn decode(s: &mut D) -> Span {
-        let lo = Decodable::decode(s);
-        let hi = Decodable::decode(s);
+
+pub trait SpanDecoder: Decoder {
+    fn decode_span(&mut self) -> Span;
+}
+
+impl SpanDecoder for MemDecoder<'_> {
+    fn decode_span(&mut self) -> Span {
+        let lo = Decodable::decode(self);
+        let hi = Decodable::decode(self);
 
         Span::new(lo, hi, SyntaxContext::root(), None)
     }
 }
 
+impl<D: SpanDecoder> Decodable<D> for Span {
+    fn decode(s: &mut D) -> Span {
+        s.decode_span()
+    }
+}
+
 /// Insert `source_map` into the session globals for the duration of the
 /// closure's execution.
 pub fn set_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
@@ -1360,7 +1384,7 @@ impl Clone for SourceFile {
     }
 }
 
-impl<S: Encoder> Encodable<S> for SourceFile {
+impl<S: SpanEncoder> Encodable<S> for SourceFile {
     fn encode(&self, s: &mut S) {
         self.name.encode(s);
         self.src_hash.encode(s);
@@ -1434,7 +1458,7 @@ impl<S: Encoder> Encodable<S> for SourceFile {
     }
 }
 
-impl<D: Decoder> Decodable<D> for SourceFile {
+impl<D: SpanDecoder> Decodable<D> for SourceFile {
     fn decode(d: &mut D) -> SourceFile {
         let name: FileName = Decodable::decode(d);
         let src_hash: SourceFileHash = Decodable::decode(d);
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 38f0eb82180..3a94256f402 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -10,6 +10,7 @@ derivative = "2.2.0"
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
 rustc_index = { path = "../rustc_index", default-features = false }
 rustc_macros = { path = "../rustc_macros", optional = true }
+rustc_span = { path = "../rustc_span", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true }
 smallvec = { version = "1.8.1" }
 # tidy-alphabetical-end
@@ -20,6 +21,7 @@ nightly = [
     "smallvec/may_dangle",
     "smallvec/union",
     "rustc_index/nightly",
+    "rustc_span",
     "rustc_serialize",
     "rustc_data_structures",
     "rustc_macros",
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index 2fbc8f76fa4..71f9eb0ef8a 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -1,7 +1,7 @@
 use crate::{Interner, PredicateKind};
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_serialize::{Decoder, Encoder};
+use rustc_span::{SpanDecoder, SpanEncoder};
 
 /// The shorthand encoding uses an enum's variant index `usize`
 /// and is offset by this value so it never matches a real variant.
@@ -22,7 +22,7 @@ pub trait RefDecodable<'tcx, D: TyDecoder> {
     fn decode(d: &mut D) -> &'tcx Self;
 }
 
-pub trait TyEncoder: Encoder {
+pub trait TyEncoder: SpanEncoder {
     type I: Interner;
     const CLEAR_CROSS_CRATE: bool;
 
@@ -35,7 +35,7 @@ pub trait TyEncoder: Encoder {
     fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
 }
 
-pub trait TyDecoder: Decoder {
+pub trait TyDecoder: SpanDecoder {
     type I: Interner;
     const CLEAR_CROSS_CRATE: bool;