about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs51
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs9
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs14
-rw-r--r--compiler/rustc_span/src/hygiene.rs139
4 files changed, 116 insertions, 97 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index d28ebfe107c..d39ac588026 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<DecodeContext<'a, 'tcx>> 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 5c7d84e2bc9..ba6d2d74aa7 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<EncodeContext<'a, 'tcx>> for SyntaxContext {
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> 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 e3db0d2cf30..85e84d6a0f4 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<CacheDecoder<'a, 'tcx>> for SyntaxContext {
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
     fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         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 d292f652896..ddf9e7b4255 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<Vec<Option<ExpnId>>>,
 }
 
-pub fn decode_expn_id<'a, D: Decoder, G>(
+pub fn decode_expn_id_incrcomp<D: Decoder>(
     d: &mut D,
-    mode: ExpnDataDecodeMode<'a, G>,
+    context: &HygieneDecodeContext,
     decode_data: impl FnOnce(&mut D, u32) -> Result<(ExpnData, ExpnHash), D::Error>,
-) -> Result<ExpnId, D::Error>
-where
-    G: FnOnce(CrateNum) -> &'a HygieneDecodeContext,
-{
+) -> Result<ExpnId, D::Error> {
     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<ExpnId, D::Error> {
+    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<E: Encoder>(
     ctxt.0.encode(e)
 }
 
-pub fn raw_encode_expn_id<E: Encoder>(
+pub fn raw_encode_expn_id_incrcomp<E: Encoder>(
     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<Span>` 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<dyn FnOnce(CrateNum) -> &'a HygieneDecodeContext>> {
-    pub fn incr_comp(ctxt: &'a HygieneDecodeContext) -> Self {
-        ExpnDataDecodeMode::IncrComp(ctxt)
+pub fn raw_encode_expn_id<E: Encoder>(
+    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<Span>` 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<E: Encoder> Encodable<E> for SyntaxContext {