diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d28ebfe107cdd..d39ac588026b0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -30,7 +30,6 @@ use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::Session; -use rustc_span::hygiene::ExpnDataDecodeMode; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; @@ -381,33 +380,29 @@ impl<'a, 'tcx> Decodable> for ExpnId { } }; - rustc_span::hygiene::decode_expn_id( - decoder, - ExpnDataDecodeMode::Metadata(get_ctxt), - |_this, index| { - let cnum = expn_cnum.get().unwrap(); - // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s - // are stored in the owning crate, to avoid duplication. - let crate_data = if cnum == LOCAL_CRATE { - local_cdata - } else { - local_cdata.cstore.get_crate_data(cnum) - }; - let expn_data = crate_data - .root - .expn_data - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - let expn_hash = crate_data - .root - .expn_hashes - .get(&crate_data, index) - .unwrap() - .decode((&crate_data, sess)); - Ok((expn_data, expn_hash)) - }, - ) + rustc_span::hygiene::decode_expn_id(decoder, get_ctxt, |_this, index| { + let cnum = expn_cnum.get().unwrap(); + // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s + // are stored in the owning crate, to avoid duplication. + let crate_data = if cnum == LOCAL_CRATE { + local_cdata + } else { + local_cdata.cstore.get_crate_data(cnum) + }; + let expn_data = crate_data + .root + .expn_data + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + let expn_hash = crate_data + .root + .expn_hashes + .get(&crate_data, index) + .unwrap() + .decode((&crate_data, sess)); + Ok((expn_data, expn_hash)) + }) } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5c7d84e2bc97f..ba6d2d74aa7ff 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -31,7 +31,7 @@ use rustc_session::config::CrateType; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ - hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind}, + hygiene::{HygieneEncodeContext, MacroKind}, RealFileName, }; use rustc_target::abi::VariantIdx; @@ -176,12 +176,7 @@ impl<'a, 'tcx> Encodable> for SyntaxContext { impl<'a, 'tcx> Encodable> for ExpnId { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - rustc_span::hygiene::raw_encode_expn_id( - *self, - &s.hygiene_ctxt, - ExpnDataEncodeMode::Metadata, - s, - ) + rustc_span::hygiene::raw_encode_expn_id(*self, &s.hygiene_ctxt, s) } } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index e3db0d2cf30a6..85e84d6a0f487 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -20,8 +20,7 @@ use rustc_serialize::{ }; use rustc_session::Session; use rustc_span::hygiene::{ - ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, - SyntaxContext, SyntaxContextData, + ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; @@ -793,9 +792,9 @@ impl<'a, 'tcx> Decodable> for SyntaxContext { impl<'a, 'tcx> Decodable> for ExpnId { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { let expn_data = decoder.expn_data; - rustc_span::hygiene::decode_expn_id( + rustc_span::hygiene::decode_expn_id_incrcomp( decoder, - ExpnDataDecodeMode::incr_comp(decoder.hygiene_context), + decoder.hygiene_context, |this, index| { // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing. // We look up the position of the associated `ExpnData` and decode it. @@ -983,12 +982,7 @@ where E: 'a + OpaqueEncoder, { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { - rustc_span::hygiene::raw_encode_expn_id( - *self, - s.hygiene_context, - ExpnDataEncodeMode::IncrComp, - s, - ) + rustc_span::hygiene::raw_encode_expn_id_incrcomp(*self, s.hygiene_context, s) } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index d292f652896f1..ddf9e7b4255c6 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1076,22 +1076,74 @@ pub struct HygieneDecodeContext { remapped_expns: Lock>>, } -pub fn decode_expn_id<'a, D: Decoder, G>( +pub fn decode_expn_id_incrcomp( d: &mut D, - mode: ExpnDataDecodeMode<'a, G>, + context: &HygieneDecodeContext, decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, -) -> Result -where - G: FnOnce(CrateNum) -> &'a HygieneDecodeContext, -{ +) -> Result { let index = u32::decode(d)?; - let context = match mode { - ExpnDataDecodeMode::IncrComp(context) => context, - ExpnDataDecodeMode::Metadata(get_context) => { - let krate = CrateNum::decode(d)?; - get_context(krate) + + // Do this after decoding, so that we decode a `CrateNum` + // if necessary + if index == ExpnId::root().as_u32() { + debug!("decode_expn_id: deserialized root"); + return Ok(ExpnId::root()); + } + + let outer_expns = &context.remapped_expns; + + // Ensure that the lock() temporary is dropped early + { + if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() { + return Ok(expn_id); } - }; + } + + // Don't decode the data inside `HygieneData::with`, since we need to recursively decode + // other ExpnIds + let (mut expn_data, hash) = decode_data(d, index)?; + + let expn_id = HygieneData::with(|hygiene_data| { + if let Some(&expn_id) = hygiene_data.expn_hash_to_expn_id.get(&hash) { + return expn_id; + } + + let expn_id = ExpnId(hygiene_data.expn_data.len() as u32); + + // If we just deserialized an `ExpnData` owned by + // the local crate, its `orig_id` will be stale, + // so we need to update it to its own value. + // This only happens when we deserialize the incremental cache, + // since a crate will never decode its own metadata. + if expn_data.krate == LOCAL_CRATE { + expn_data.orig_id = Some(expn_id.0); + } + + hygiene_data.expn_data.push(Some(expn_data)); + hygiene_data.expn_hashes.push(hash); + let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id); + debug_assert!(_old_id.is_none()); + + let mut expns = outer_expns.lock(); + let new_len = index as usize + 1; + if expns.len() < new_len { + expns.resize(new_len, None); + } + expns[index as usize] = Some(expn_id); + drop(expns); + expn_id + }); + Ok(expn_id) +} + +pub fn decode_expn_id<'a, D: Decoder>( + d: &mut D, + get_context: impl FnOnce(CrateNum) -> &'a HygieneDecodeContext, + decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>, +) -> Result { + let index = u32::decode(d)?; + let krate = CrateNum::decode(d)?; + let context = get_context(krate); // Do this after decoding, so that we decode a `CrateNum` // if necessary @@ -1274,56 +1326,39 @@ pub fn raw_encode_syntax_context( ctxt.0.encode(e) } -pub fn raw_encode_expn_id( +pub fn raw_encode_expn_id_incrcomp( expn: ExpnId, context: &HygieneEncodeContext, - mode: ExpnDataEncodeMode, e: &mut E, ) -> Result<(), E::Error> { // Record the fact that we need to serialize the corresponding // `ExpnData` - let needs_data = || { - if !context.serialized_expns.lock().contains(&expn) { - context.latest_expns.lock().insert(expn); - } - }; - - match mode { - ExpnDataEncodeMode::IncrComp => { - // Always serialize the `ExpnData` in incr comp mode - needs_data(); - expn.0.encode(e) - } - ExpnDataEncodeMode::Metadata => { - let data = expn.expn_data(); - // We only need to serialize the ExpnData - // if it comes from this crate. - // We currently don't serialize any hygiene information data for - // proc-macro crates: see the `SpecializedEncoder` impl - // for crate metadata. - if data.krate == LOCAL_CRATE { - needs_data(); - } - data.orig_id.expect("Missing orig_id").encode(e)?; - data.krate.encode(e) - } + if !context.serialized_expns.lock().contains(&expn) { + context.latest_expns.lock().insert(expn); } + expn.0.encode(e) } -pub enum ExpnDataEncodeMode { - IncrComp, - Metadata, -} - -pub enum ExpnDataDecodeMode<'a, F: FnOnce(CrateNum) -> &'a HygieneDecodeContext> { - IncrComp(&'a HygieneDecodeContext), - Metadata(F), -} - -impl<'a> ExpnDataDecodeMode<'a, Box &'a HygieneDecodeContext>> { - pub fn incr_comp(ctxt: &'a HygieneDecodeContext) -> Self { - ExpnDataDecodeMode::IncrComp(ctxt) +pub fn raw_encode_expn_id( + expn: ExpnId, + context: &HygieneEncodeContext, + e: &mut E, +) -> Result<(), E::Error> { + let data = expn.expn_data(); + // We only need to serialize the ExpnData + // if it comes from this crate. + // We currently don't serialize any hygiene information data for + // proc-macro crates: see the `SpecializedEncoder` impl + // for crate metadata. + if data.krate == LOCAL_CRATE { + // Record the fact that we need to serialize the corresponding + // `ExpnData` + if !context.serialized_expns.lock().contains(&expn) { + context.latest_expns.lock().insert(expn); + } } + data.orig_id.expect("Missing orig_id").encode(e)?; + data.krate.encode(e) } impl Encodable for SyntaxContext {