use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder};
use rustc_session::config::CrateType;
-use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
+use rustc_span::{
+ hygiene::{ExpnDataEncodeMode, HygieneEncodeContext, MacroKind},
+ RealFileName,
+};
use rustc_target::abi::VariantIdx;
use std::hash::Hash;
use std::num::NonZeroUsize;
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
- if *self == rustc_span::DUMMY_SP {
- return TAG_INVALID_SPAN.encode(s);
+ let span = self.data();
+
+ // Don't serialize any `SyntaxContext`s from a proc-macro crate,
+ // since we don't load proc-macro dependencies during serialization.
+ // This means that any hygiene information from macros used *within*
+ // a proc-macro crate (e.g. invoking a macro that expands to a proc-macro
+ // definition) will be lost.
+ //
+ // This can show up in two ways:
+ //
+ // 1. Any hygiene information associated with identifier of
+ // a proc macro (e.g. `#[proc_macro] pub fn $name`) will be lost.
+ // Since proc-macros can only be invoked from a different crate,
+ // real code should never need to care about this.
+ //
+ // 2. Using `Span::def_site` or `Span::mixed_site` will not
+ // include any hygiene information associated with the definition
+ // site. This means that a proc-macro cannot emit a `$crate`
+ // identifier which resolves to one of its dependencies,
+ // which also should never come up in practice.
+ //
+ // Additionally, this affects `Span::parent`, and any other
+ // span inspection APIs that would otherwise allow traversing
+ // the `SyntaxContexts` associated with a span.
+ //
+ // None of these user-visible effects should result in any
+ // cross-crate inconsistencies (getting one behavior in the same
+ // crate, and a different behavior in another crate) due to the
+ // limited surface that proc-macros can expose.
+ //
+ // IMPORTANT: If this is ever changed, be sure to update
+ // `rustc_span::hygiene::raw_encode_expn_id` to handle
+ // encoding `ExpnData` for proc-macro crates.
+ if s.is_proc_macro {
+ SyntaxContext::root().encode(s)?;
+ } else {
+ span.ctxt.encode(s)?;
}
- let span = self.data();
+ if self.is_dummy() {
+ return TAG_PARTIAL_SPAN.encode(s);
+ }
// The Span infrastructure should make sure that this invariant holds:
debug_assert!(span.lo <= span.hi);
if !s.source_file_cache.0.contains(span.hi) {
// Unfortunately, macro expansion still sometimes generates Spans
// that malformed in this way.
- return TAG_INVALID_SPAN.encode(s);
+ return TAG_PARTIAL_SPAN.encode(s);
}
let source_files = s.required_source_files.as_mut().expect("Already encoded SourceMap!");
let len = hi - lo;
len.encode(s)?;
- // Don't serialize any `SyntaxContext`s from a proc-macro crate,
- // since we don't load proc-macro dependencies during serialization.
- // This means that any hygiene information from macros used *within*
- // a proc-macro crate (e.g. invoking a macro that expands to a proc-macro
- // definition) will be lost.
- //
- // This can show up in two ways:
- //
- // 1. Any hygiene information associated with identifier of
- // a proc macro (e.g. `#[proc_macro] pub fn $name`) will be lost.
- // Since proc-macros can only be invoked from a different crate,
- // real code should never need to care about this.
- //
- // 2. Using `Span::def_site` or `Span::mixed_site` will not
- // include any hygiene information associated with the definition
- // site. This means that a proc-macro cannot emit a `$crate`
- // identifier which resolves to one of its dependencies,
- // which also should never come up in practice.
- //
- // Additionally, this affects `Span::parent`, and any other
- // span inspection APIs that would otherwise allow traversing
- // the `SyntaxContexts` associated with a span.
- //
- // None of these user-visible effects should result in any
- // cross-crate inconsistencies (getting one behavior in the same
- // crate, and a different behavior in another crate) due to the
- // limited surface that proc-macros can expose.
- //
- // IMPORTANT: If this is ever changed, be sure to update
- // `rustc_span::hygiene::raw_encode_expn_id` to handle
- // encoding `ExpnData` for proc-macro crates.
- if s.is_proc_macro {
- SyntaxContext::root().encode(s)?;
- } else {
- span.ctxt.encode(s)?;
- }
-
if tag == TAG_VALID_SPAN_FOREIGN {
// This needs to be two lines to avoid holding the `s.source_file_cache`
// while calling `cnum.encode(s)`
let source_map = self.tcx.sess.source_map();
let all_source_files = source_map.files();
- let (working_dir, _cwd_remapped) = self.tcx.sess.working_dir.clone();
// By replacing the `Option` with `None`, we ensure that we can't
// accidentally serialize any more `Span`s after the source map encoding
// is done.
})
.map(|(_, source_file)| {
let mut adapted = match source_file.name {
- // This path of this SourceFile has been modified by
- // path-remapping, so we use it verbatim (and avoid
- // cloning the whole map in the process).
- _ if source_file.name_was_remapped => source_file.clone(),
-
- // Otherwise expand all paths to absolute paths because
- // any relative paths are potentially relative to a
- // wrong directory.
- FileName::Real(ref name) => {
- let name = name.stable_name();
+ FileName::Real(ref realname) => {
let mut adapted = (**source_file).clone();
- adapted.name = Path::new(&working_dir).join(name).into();
+ adapted.name = FileName::Real(match realname {
+ RealFileName::LocalPath(path_to_file) => {
+ // Prepend path of working directory onto potentially
+ // relative paths, because they could become relative
+ // to a wrong directory.
+ let working_dir = &self.tcx.sess.working_dir;
+ match working_dir {
+ RealFileName::LocalPath(absolute) => {
+ // If working_dir has not been remapped, then we emit a
+ // LocalPath variant as it's likely to be a valid path
+ RealFileName::LocalPath(
+ Path::new(absolute).join(path_to_file),
+ )
+ }
+ RealFileName::Remapped { local_path: _, virtual_name } => {
+ // If working_dir has been remapped, then we emit
+ // Remapped variant as the expanded path won't be valid
+ RealFileName::Remapped {
+ local_path: None,
+ virtual_name: Path::new(virtual_name)
+ .join(path_to_file),
+ }
+ }
+ }
+ }
+ RealFileName::Remapped { local_path: _, virtual_name } => {
+ RealFileName::Remapped {
+ // We do not want any local path to be exported into metadata
+ local_path: None,
+ virtual_name: virtual_name.clone(),
+ }
+ }
+ });
adapted.name_hash = {
let mut hasher: StableHasher = StableHasher::new();
adapted.name.hash(&mut hasher);