diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 55daf441a75..ae4a0e15fab 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -507,10 +507,18 @@ impl<'a, 'tcx> Decodable> for ExpnId { impl<'a, 'tcx> Decodable> for Span { fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span { + let start = decoder.position(); let mode = SpanEncodingMode::decode(decoder); let data = match mode { SpanEncodingMode::Direct => SpanData::decode(decoder), - SpanEncodingMode::Shorthand(position) => decoder.with_position(position, |decoder| { + SpanEncodingMode::RelativeOffset(offset) => { + decoder.with_position(start - offset, |decoder| { + let mode = SpanEncodingMode::decode(decoder); + debug_assert!(matches!(mode, SpanEncodingMode::Direct)); + SpanData::decode(decoder) + }) + } + SpanEncodingMode::AbsoluteOffset(addr) => decoder.with_position(addr, |decoder| { let mode = SpanEncodingMode::decode(decoder); debug_assert!(matches!(mode, SpanEncodingMode::Direct)); SpanData::decode(decoder) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 411a70f9f1b..513c49efc8e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -169,7 +169,19 @@ impl<'a, 'tcx> Encodable> for ExpnId { impl<'a, 'tcx> Encodable> for Span { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) { match s.span_shorthands.entry(*self) { - Entry::Occupied(o) => SpanEncodingMode::Shorthand(*o.get()).encode(s), + 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; + if offset < last_location { + SpanEncodingMode::RelativeOffset(offset).encode(s) + } else { + SpanEncodingMode::AbsoluteOffset(last_location).encode(s) + } + } Entry::Vacant(v) => { let position = s.opaque.position(); v.insert(position); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d496e7494e7..bafd3f0b84d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -68,7 +68,8 @@ pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_V #[derive(Encodable, Decodable)] enum SpanEncodingMode { - Shorthand(usize), + RelativeOffset(usize), + AbsoluteOffset(usize), Direct, }