summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_span
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /compiler/rustc_span
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_span')
-rw-r--r--compiler/rustc_span/Cargo.toml4
-rw-r--r--compiler/rustc_span/src/analyze_source_file.rs4
-rw-r--r--compiler/rustc_span/src/def_id.rs16
-rw-r--r--compiler/rustc_span/src/edition.rs2
-rw-r--r--compiler/rustc_span/src/hygiene.rs37
-rw-r--r--compiler/rustc_span/src/lib.rs25
-rw-r--r--compiler/rustc_span/src/profiling.rs2
-rw-r--r--compiler/rustc_span/src/source_map.rs141
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs45
-rw-r--r--compiler/rustc_span/src/span_encoding.rs86
-rw-r--r--compiler/rustc_span/src/symbol.rs19
11 files changed, 274 insertions, 107 deletions
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 48a2ab0f9..ae81d95e2 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -13,8 +13,8 @@ rustc_index = { path = "../rustc_index" }
rustc_arena = { path = "../rustc_arena" }
scoped-tls = "1.0"
unicode-width = "0.1.4"
-cfg-if = "0.1.2"
+cfg-if = "1.0"
tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.10.0" }
+sha1 = "0.10.0"
sha2 = "0.10.1"
md5 = { package = "md-5", version = "0.10.0" }
diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs
index d3c2c5113..26cd54210 100644
--- a/compiler/rustc_span/src/analyze_source_file.rs
+++ b/compiler/rustc_span/src/analyze_source_file.rs
@@ -175,7 +175,7 @@ cfg_if::cfg_if! {
// There might still be a tail left to analyze
let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset;
if tail_start < src.len() {
- analyze_source_file_generic(&src[tail_start as usize ..],
+ analyze_source_file_generic(&src[tail_start ..],
src.len() - tail_start,
output_offset + BytePos::from_usize(tail_start),
lines,
@@ -219,7 +219,7 @@ fn analyze_source_file_generic(
while i < scan_len {
let byte = unsafe {
// We verified that i < scan_len <= src.len()
- *src_bytes.get_unchecked(i as usize)
+ *src_bytes.get_unchecked(i)
};
// How much to advance in order to get to the next UTF-8 char in the
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index e62ce2c26..7c5e1427d 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -10,10 +10,9 @@ use std::fmt;
use std::hash::{Hash, Hasher};
rustc_index::newtype_index! {
- pub struct CrateNum {
- ENCODABLE = custom
- DEBUG_FORMAT = "crate{}"
- }
+ #[custom_encodable]
+ #[debug_format = "crate{}"]
+ pub struct CrateNum {}
}
/// Item definitions in the currently-compiled crate would have the `CrateNum`
@@ -194,13 +193,12 @@ rustc_index::newtype_index! {
/// A DefIndex is an index into the hir-map for a crate, identifying a
/// particular definition. It should really be considered an interned
/// shorthand for a particular DefPath.
+ #[custom_encodable] // (only encodable in metadata)
+ #[debug_format = "DefIndex({})"]
pub struct DefIndex {
- ENCODABLE = custom // (only encodable in metadata)
-
- DEBUG_FORMAT = "DefIndex({})",
/// The crate root is always assigned index 0 by the AST Map code,
/// thanks to `NodeCollector::new`.
- const CRATE_DEF_INDEX = 0,
+ const CRATE_DEF_INDEX = 0;
}
}
@@ -305,7 +303,7 @@ impl DefId {
// i.e. don't use closures.
match self.as_local() {
Some(local_def_id) => local_def_id,
- None => panic!("DefId::expect_local: `{:?}` isn't local", self),
+ None => panic!("DefId::expect_local: `{self:?}` isn't local"),
}
}
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index 065d3660e..b43183916 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -44,7 +44,7 @@ impl fmt::Display for Edition {
Edition::Edition2021 => "2021",
Edition::Edition2024 => "2024",
};
- write!(f, "{}", s)
+ write!(f, "{s}")
}
}
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 038699154..dee823eef 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -61,9 +61,8 @@ pub struct SyntaxContextData {
rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
- pub struct ExpnIndex {
- ENCODABLE = custom
- }
+ #[custom_encodable]
+ pub struct ExpnIndex {}
}
/// A unique ID associated with a macro invocation and expansion.
@@ -82,11 +81,10 @@ impl fmt::Debug for ExpnId {
rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
- pub struct LocalExpnId {
- ENCODABLE = custom
- ORD_IMPL = custom
- DEBUG_FORMAT = "expn{}"
- }
+ #[custom_encodable]
+ #[no_ord_impl]
+ #[debug_format = "expn{}"]
+ pub struct LocalExpnId {}
}
// To ensure correctness of incremental compilation,
@@ -106,9 +104,13 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str)
// `-Z incremental-ignore-spans` option. Normally, this option is disabled,
// which will cause us to require that this method always be called with `Span` hashing
// enabled.
+ //
+ // Span hashing can also be disabled without `-Z incremental-ignore-spans`.
+ // This is the case for instance when building a hash for name mangling.
+ // Such configuration must not be used for metadata.
HashingControls { hash_spans }
if hash_spans == !ctx.unstable_opts_incremental_ignore_spans() => {}
- other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+ other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
}
}
@@ -318,6 +320,7 @@ impl ExpnId {
// Stop going up the backtrace once include! is encountered
if expn_data.is_root()
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
+ || expn_data.kind == ExpnKind::Inlined
{
break;
}
@@ -335,7 +338,7 @@ pub struct HygieneData {
/// first and then resolved later), so we use an `Option` here.
local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
- /// Data and hash information from external crates. We may eventually want to remove these
+ /// Data and hash information from external crates. We may eventually want to remove these
/// maps, and fetch the information directly from the other crate's metadata like DefIds do.
foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
@@ -626,7 +629,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb
pub fn debug_hygiene_data(verbose: bool) -> String {
HygieneData::with(|data| {
if verbose {
- format!("{:#?}", data)
+ format!("{data:#?}")
} else {
let mut s = String::from("Expansions:");
let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
@@ -1064,9 +1067,9 @@ impl ExpnKind {
match *self {
ExpnKind::Root => kw::PathRoot.to_string(),
ExpnKind::Macro(macro_kind, name) => match macro_kind {
- MacroKind::Bang => format!("{}!", name),
- MacroKind::Attr => format!("#[{}]", name),
- MacroKind::Derive => format!("#[derive({})]", name),
+ MacroKind::Bang => format!("{name}!"),
+ MacroKind::Attr => format!("#[{name}]"),
+ MacroKind::Derive => format!("#[derive({name})]"),
},
ExpnKind::AstPass(kind) => kind.descr().to_string(),
ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
@@ -1463,11 +1466,7 @@ impl<D: Decoder> Decodable<D> for SyntaxContext {
/// collisions are only possible between `ExpnId`s within the same crate.
fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
// This disambiguator should not have been set yet.
- assert_eq!(
- expn_data.disambiguator, 0,
- "Already set disambiguator for ExpnData: {:?}",
- expn_data
- );
+ assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
let mut expn_hash = expn_data.hash_expn(&mut ctx);
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index cef4c6f79..7e61f2f9f 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -259,6 +259,10 @@ impl RealFileName {
FileNameDisplayPreference::Remapped => {
self.remapped_path_if_available().to_string_lossy()
}
+ FileNameDisplayPreference::Short => self
+ .local_path_if_available()
+ .file_name()
+ .map_or_else(|| "".into(), |f| f.to_string_lossy()),
}
}
}
@@ -302,6 +306,9 @@ pub enum FileNameDisplayPreference {
/// Display the path before the application of rewrite rules provided via `--remap-path-prefix`.
/// This is appropriate for use in user-facing output (such as diagnostics).
Local,
+ /// Display only the filename, as a way to reduce the verbosity of the output.
+ /// This is appropriate for use in user-facing output (such as diagnostics).
+ Short,
}
pub struct FileNameDisplay<'a> {
@@ -322,7 +329,7 @@ impl fmt::Display for FileNameDisplay<'_> {
ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"),
CfgSpec(_) => write!(fmt, "<cfgspec>"),
CliCrateAttr(_) => write!(fmt, "<crate attribute>"),
- Custom(ref s) => write!(fmt, "<{}>", s),
+ Custom(ref s) => write!(fmt, "<{s}>"),
DocTest(ref path, _) => write!(fmt, "{}", path.display()),
InlineAsm(_) => write!(fmt, "<inline asm>"),
}
@@ -491,6 +498,10 @@ impl SpanData {
pub fn is_dummy(self) -> bool {
self.lo.0 == 0 && self.hi.0 == 0
}
+ #[inline]
+ pub fn is_visible(self, sm: &SourceMap) -> bool {
+ !self.is_dummy() && sm.is_span_accessible(self.span())
+ }
/// Returns `true` if `self` fully encloses `other`.
pub fn contains(self, other: Self) -> bool {
self.lo <= other.lo && other.hi <= self.hi
@@ -556,6 +567,11 @@ impl Span {
self.data_untracked().is_dummy()
}
+ #[inline]
+ pub fn is_visible(self, sm: &SourceMap) -> bool {
+ self.data_untracked().is_visible(sm)
+ }
+
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
#[inline]
pub fn from_expansion(self) -> bool {
@@ -780,6 +796,9 @@ impl Span {
/// Returns a `Span` that would enclose both `self` and `end`.
///
+ /// Note that this can also be used to extend the span "backwards":
+ /// `start.to(end)` and `end.to(start)` return the same `Span`.
+ ///
/// ```text
/// ____ ___
/// self lorem ipsum end
@@ -1055,7 +1074,7 @@ impl NonNarrowChar {
0 => NonNarrowChar::ZeroWidth(pos),
2 => NonNarrowChar::Wide(pos),
4 => NonNarrowChar::Tab(pos),
- _ => panic!("width {} given for non-narrow character", width),
+ _ => panic!("width {width} given for non-narrow character"),
}
}
@@ -1372,7 +1391,7 @@ impl<S: Encoder> Encodable<S> for SourceFile {
4 => {
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
for diff in diff_iter {
- raw_diffs.extend_from_slice(&(diff.0 as u32).to_le_bytes());
+ raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
}
}
_ => unreachable!(),
diff --git a/compiler/rustc_span/src/profiling.rs b/compiler/rustc_span/src/profiling.rs
index f169007fa..0ab890b9f 100644
--- a/compiler/rustc_span/src/profiling.rs
+++ b/compiler/rustc_span/src/profiling.rs
@@ -27,7 +27,7 @@ impl SpannedEventArgRecorder for EventArgRecorder<'_> {
if let Some(source_map) = &*session_globals.source_map.borrow() {
source_map.span_to_embeddable_string(span)
} else {
- format!("{:?}", span)
+ format!("{span:?}")
}
});
self.record_arg(span_arg);
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 2ae57d9e5..2e339a9d2 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -15,11 +15,10 @@ pub use crate::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
+use std::cmp;
use std::hash::Hash;
-use std::path::{Path, PathBuf};
+use std::path::{self, Path, PathBuf};
use std::sync::atomic::Ordering;
-use std::{clone::Clone, cmp};
-use std::{convert::TryFrom, unreachable};
use std::fs;
use std::io;
@@ -439,7 +438,11 @@ impl SourceMap {
}
}
- fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
+ pub fn span_to_string(
+ &self,
+ sp: Span,
+ filename_display_pref: FileNameDisplayPreference,
+ ) -> String {
if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
return "no-location".to_string();
}
@@ -447,12 +450,15 @@ impl SourceMap {
let lo = self.lookup_char_pos(sp.lo());
let hi = self.lookup_char_pos(sp.hi());
format!(
- "{}:{}:{}: {}:{}",
+ "{}:{}:{}{}",
lo.file.name.display(filename_display_pref),
lo.line,
lo.col.to_usize() + 1,
- hi.line,
- hi.col.to_usize() + 1,
+ if let FileNameDisplayPreference::Short = filename_display_pref {
+ String::new()
+ } else {
+ format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
+ }
)
}
@@ -942,7 +948,7 @@ impl SourceMap {
/// Otherwise, the span reached to limit is returned.
pub fn span_look_ahead(&self, span: Span, expect: Option<&str>, limit: Option<usize>) -> Span {
let mut sp = span;
- for _ in 0..limit.unwrap_or(100 as usize) {
+ for _ in 0..limit.unwrap_or(100_usize) {
sp = self.next_point(sp);
if let Ok(ref snippet) = self.span_to_snippet(sp) {
if expect.map_or(false, |es| snippet == es) {
@@ -958,45 +964,40 @@ impl SourceMap {
/// Finds the width of the character, either before or after the end of provided span,
/// depending on the `forwards` parameter.
+ #[instrument(skip(self, sp))]
fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
let sp = sp.data();
if sp.lo == sp.hi && !forwards {
- debug!("find_width_of_character_at_span: early return empty span");
+ debug!("early return empty span");
return 1;
}
let local_begin = self.lookup_byte_offset(sp.lo);
let local_end = self.lookup_byte_offset(sp.hi);
- debug!(
- "find_width_of_character_at_span: local_begin=`{:?}`, local_end=`{:?}`",
- local_begin, local_end
- );
+ debug!("local_begin=`{:?}`, local_end=`{:?}`", local_begin, local_end);
if local_begin.sf.start_pos != local_end.sf.start_pos {
- debug!("find_width_of_character_at_span: begin and end are in different files");
+ debug!("begin and end are in different files");
return 1;
}
let start_index = local_begin.pos.to_usize();
let end_index = local_end.pos.to_usize();
- debug!(
- "find_width_of_character_at_span: start_index=`{:?}`, end_index=`{:?}`",
- start_index, end_index
- );
+ debug!("start_index=`{:?}`, end_index=`{:?}`", start_index, end_index);
// Disregard indexes that are at the start or end of their spans, they can't fit bigger
// characters.
if (!forwards && end_index == usize::MIN) || (forwards && start_index == usize::MAX) {
- debug!("find_width_of_character_at_span: start or end of span, cannot be multibyte");
+ debug!("start or end of span, cannot be multibyte");
return 1;
}
let source_len = (local_begin.sf.end_pos - local_begin.sf.start_pos).to_usize();
- debug!("find_width_of_character_at_span: source_len=`{:?}`", source_len);
+ debug!("source_len=`{:?}`", source_len);
// Ensure indexes are also not malformed.
if start_index > end_index || end_index > source_len - 1 {
- debug!("find_width_of_character_at_span: source indexes are malformed");
+ debug!("source indexes are malformed");
return 1;
}
@@ -1011,10 +1012,10 @@ impl SourceMap {
} else {
return 1;
};
- debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
+ debug!("snippet=`{:?}`", snippet);
let mut target = if forwards { end_index + 1 } else { end_index - 1 };
- debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
+ debug!("initial target=`{:?}`", target);
while !snippet.is_char_boundary(target - start_index) && target < source_len {
target = if forwards {
@@ -1027,9 +1028,9 @@ impl SourceMap {
}
}
};
- debug!("find_width_of_character_at_span: target=`{:?}`", target);
+ debug!("target=`{:?}`", target);
}
- debug!("find_width_of_character_at_span: final target=`{:?}`", target);
+ debug!("final target=`{:?}`", target);
if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 }
}
@@ -1070,12 +1071,24 @@ impl SourceMap {
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
source_file.add_external_src(|| {
- match source_file.name {
- FileName::Real(ref name) if let Some(local_path) = name.local_path() => {
- self.file_loader.read_file(local_path).ok()
+ let FileName::Real(ref name) = source_file.name else {
+ return None;
+ };
+
+ let local_path: Cow<'_, Path> = match name {
+ RealFileName::LocalPath(local_path) => local_path.into(),
+ RealFileName::Remapped { local_path: Some(local_path), .. } => local_path.into(),
+ RealFileName::Remapped { local_path: None, virtual_name } => {
+ // The compiler produces better error messages if the sources of dependencies
+ // are available. Attempt to undo any path mapping so we can find remapped
+ // dependencies.
+ // We can only use the heuristic because `add_external_src` checks the file
+ // content hash.
+ self.path_mapping.reverse_map_prefix_heuristically(virtual_name)?.into()
}
- _ => None,
- }
+ };
+
+ self.file_loader.read_file(&local_path).ok()
})
}
@@ -1137,7 +1150,8 @@ impl FilePathMapping {
/// Applies any path prefix substitution as defined by the mapping.
/// The return value is the remapped path and a boolean indicating whether
/// the path was affected by the mapping.
- pub fn map_prefix(&self, path: PathBuf) -> (PathBuf, bool) {
+ pub fn map_prefix<'a>(&'a self, path: impl Into<Cow<'a, Path>>) -> (Cow<'a, Path>, bool) {
+ let path = path.into();
if path.as_os_str().is_empty() {
// Exit early if the path is empty and therefore there's nothing to remap.
// This is mostly to reduce spam for `RUSTC_LOG=[remap_path_prefix]`.
@@ -1147,11 +1161,14 @@ impl FilePathMapping {
return remap_path_prefix(&self.mapping, path);
#[instrument(level = "debug", skip(mapping), ret)]
- fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) {
+ fn remap_path_prefix<'a>(
+ mapping: &'a [(PathBuf, PathBuf)],
+ path: Cow<'a, Path>,
+ ) -> (Cow<'a, Path>, bool) {
// NOTE: We are iterating over the mapping entries from last to first
// because entries specified later on the command line should
// take precedence.
- for &(ref from, ref to) in mapping.iter().rev() {
+ for (from, to) in mapping.iter().rev() {
debug!("Trying to apply {from:?} => {to:?}");
if let Ok(rest) = path.strip_prefix(from) {
@@ -1162,9 +1179,9 @@ impl FilePathMapping {
// in remapped paths down the line.
// So, if we have an exact match, we just return that without a call
// to `Path::join()`.
- to.clone()
+ to.into()
} else {
- to.join(rest)
+ to.join(rest).into()
};
debug!("Match - remapped");
@@ -1182,11 +1199,11 @@ impl FilePathMapping {
fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
match file {
FileName::Real(realfile) if let RealFileName::LocalPath(local_path) = realfile => {
- let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
+ let (mapped_path, mapped) = self.map_prefix(local_path);
let realfile = if mapped {
RealFileName::Remapped {
local_path: Some(local_path.clone()),
- virtual_name: mapped_path,
+ virtual_name: mapped_path.into_owned(),
}
} else {
realfile.clone()
@@ -1227,14 +1244,17 @@ impl FilePathMapping {
let (new_path, was_remapped) = self.map_prefix(unmapped_file_path);
if was_remapped {
// It was remapped, so don't modify further
- return RealFileName::Remapped { local_path: None, virtual_name: new_path };
+ return RealFileName::Remapped {
+ local_path: None,
+ virtual_name: new_path.into_owned(),
+ };
}
if new_path.is_absolute() {
// No remapping has applied to this path and it is absolute,
// so the working directory cannot influence it either, so
// we are done.
- return RealFileName::LocalPath(new_path);
+ return RealFileName::LocalPath(new_path.into_owned());
}
debug_assert!(new_path.is_relative());
@@ -1252,12 +1272,12 @@ impl FilePathMapping {
RealFileName::Remapped {
// Erase the actual path
local_path: None,
- virtual_name: file_path_abs,
+ virtual_name: file_path_abs.into_owned(),
}
} else {
// No kind of remapping applied to this path, so
// we leave it as it is.
- RealFileName::LocalPath(file_path_abs)
+ RealFileName::LocalPath(file_path_abs.into_owned())
}
}
RealFileName::Remapped {
@@ -1276,4 +1296,43 @@ impl FilePathMapping {
}
}
}
+
+ /// Attempts to (heuristically) reverse a prefix mapping.
+ ///
+ /// Returns [`Some`] if there is exactly one mapping where the "to" part is
+ /// a prefix of `path` and has at least one non-empty
+ /// [`Normal`](path::Component::Normal) component. The component
+ /// restriction exists to avoid reverse mapping overly generic paths like
+ /// `/` or `.`).
+ ///
+ /// This is a heuristic and not guaranteed to return the actual original
+ /// path! Do not rely on the result unless you have other means to verify
+ /// that the mapping is correct (e.g. by checking the file content hash).
+ #[instrument(level = "debug", skip(self), ret)]
+ fn reverse_map_prefix_heuristically(&self, path: &Path) -> Option<PathBuf> {
+ let mut found = None;
+
+ for (from, to) in self.mapping.iter() {
+ let has_normal_component = to.components().any(|c| match c {
+ path::Component::Normal(s) => !s.is_empty(),
+ _ => false,
+ });
+
+ if !has_normal_component {
+ continue;
+ }
+
+ let Ok(rest) = path.strip_prefix(to) else {
+ continue;
+ };
+
+ if found.is_some() {
+ return None;
+ }
+
+ found = Some(from.join(rest));
+ }
+
+ found
+ }
}
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3cab59e8d..686b3b00d 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -344,6 +344,10 @@ fn map_path_prefix(mapping: &FilePathMapping, p: &str) -> String {
mapping.map_prefix(path(p)).0.to_string_lossy().to_string()
}
+fn reverse_map_prefix(mapping: &FilePathMapping, p: &str) -> Option<String> {
+ mapping.reverse_map_prefix_heuristically(&path(p)).map(|q| q.to_string_lossy().to_string())
+}
+
#[test]
fn path_prefix_remapping() {
// Relative to relative
@@ -387,7 +391,7 @@ fn path_prefix_remapping_expand_to_absolute() {
let working_directory = path("/foo");
let working_directory = RealFileName::Remapped {
local_path: Some(working_directory.clone()),
- virtual_name: mapping.map_prefix(working_directory).0,
+ virtual_name: mapping.map_prefix(working_directory).0.into_owned(),
};
assert_eq!(working_directory.remapped_path_if_available(), path("FOO"));
@@ -481,6 +485,45 @@ fn path_prefix_remapping_expand_to_absolute() {
}
#[test]
+fn path_prefix_remapping_reverse() {
+ // Ignores options without alphanumeric chars.
+ {
+ let mapping =
+ &FilePathMapping::new(vec![(path("abc"), path("/")), (path("def"), path("."))]);
+
+ assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None);
+ assert_eq!(reverse_map_prefix(mapping, "./hello.rs"), None);
+ }
+
+ // Returns `None` if multiple options match.
+ {
+ let mapping = &FilePathMapping::new(vec![
+ (path("abc"), path("/redacted")),
+ (path("def"), path("/redacted")),
+ ]);
+
+ assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None);
+ }
+
+ // Distinct reverse mappings.
+ {
+ let mapping = &FilePathMapping::new(vec![
+ (path("abc"), path("/redacted")),
+ (path("def/ghi"), path("/fake/dir")),
+ ]);
+
+ assert_eq!(
+ reverse_map_prefix(mapping, "/redacted/path/hello.rs"),
+ Some(path_str("abc/path/hello.rs"))
+ );
+ assert_eq!(
+ reverse_map_prefix(mapping, "/fake/dir/hello.rs"),
+ Some(path_str("def/ghi/hello.rs"))
+ );
+ }
+}
+
+#[test]
fn test_next_point() {
let sm = SourceMap::new(FilePathMapping::empty());
sm.new_source_file(PathBuf::from("example.rs").into(), "a…b".to_string());
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index f0e91e5a6..d48c4f7e5 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -4,7 +4,7 @@
// The encoding format for inline spans were obtained by optimizing over crates in rustc/libstd.
// See https://internals.rust-lang.org/t/rfc-compiler-refactoring-spans/1357/28
-use crate::def_id::LocalDefId;
+use crate::def_id::{DefIndex, LocalDefId};
use crate::hygiene::SyntaxContext;
use crate::SPAN_TRACK;
use crate::{BytePos, SpanData};
@@ -13,8 +13,8 @@ use rustc_data_structures::fx::FxIndexSet;
/// A compressed span.
///
-/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
-/// is a form that only takes up 8 bytes, with less space for the length and
+/// Whereas [`SpanData`] is 16 bytes, which is a bit too big to stick everywhere, `Span`
+/// is a form that only takes up 8 bytes, with less space for the length, parent and
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
/// stored in a separate interner table, and the `Span` will index into that
@@ -25,7 +25,7 @@ use rustc_data_structures::fx::FxIndexSet;
/// slower because only 80--90% of spans could be stored inline (even less in
/// very large crates) and so the interner was used a lot more.
///
-/// Inline (compressed) format:
+/// Inline (compressed) format with no parent:
/// - `span.base_or_index == span_data.lo`
/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
@@ -35,6 +35,12 @@ use rustc_data_structures::fx::FxIndexSet;
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`)
///
+/// Inline (compressed) format with root context:
+/// - `span.base_or_index == span_data.lo`
+/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`)
+/// - `span.len_or_tag` has top bit (`PARENT_MASK`) set
+/// - `span.ctxt == span_data.parent` (must be `<= MAX_CTXT`)
+///
/// Interned format:
/// - `span.base_or_index == index` (indexes into the interner table)
/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero)
@@ -73,7 +79,8 @@ pub struct Span {
ctxt_or_tag: u16,
}
-const LEN_TAG: u16 = 0b1000_0000_0000_0000;
+const LEN_TAG: u16 = 0b1111_1111_1111_1111;
+const PARENT_MASK: u16 = 0b1000_0000_0000_0000;
const MAX_LEN: u32 = 0b0111_1111_1111_1111;
const CTXT_TAG: u32 = 0b1111_1111_1111_1111;
const MAX_CTXT: u32 = CTXT_TAG - 1;
@@ -95,16 +102,32 @@ impl Span {
let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32());
- if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() {
- // Inline format.
- Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 }
- } else {
- // Interned format.
- let index =
- with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
- let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
- Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
+ if len <= MAX_LEN && ctxt2 <= MAX_CTXT {
+ let len_or_tag = len as u16;
+ debug_assert_eq!(len_or_tag & PARENT_MASK, 0);
+
+ if let Some(parent) = parent {
+ // Inline format with parent.
+ let len_or_tag = len_or_tag | PARENT_MASK;
+ let parent2 = parent.local_def_index.as_u32();
+ if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+ return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
+ }
+ } else {
+ // Inline format with ctxt.
+ return Span {
+ base_or_index: base,
+ len_or_tag: len as u16,
+ ctxt_or_tag: ctxt2 as u16,
+ };
+ }
}
+
+ // Interned format.
+ let index =
+ with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent }));
+ let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16;
+ Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag }
}
#[inline]
@@ -122,12 +145,25 @@ impl Span {
pub fn data_untracked(self) -> SpanData {
if self.len_or_tag != LEN_TAG {
// Inline format.
- debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
- SpanData {
- lo: BytePos(self.base_or_index),
- hi: BytePos(self.base_or_index + self.len_or_tag as u32),
- ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
- parent: None,
+ if self.len_or_tag & PARENT_MASK == 0 {
+ debug_assert!(self.len_or_tag as u32 <= MAX_LEN);
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + self.len_or_tag as u32),
+ ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32),
+ parent: None,
+ }
+ } else {
+ let len = self.len_or_tag & !PARENT_MASK;
+ debug_assert!(len as u32 <= MAX_LEN);
+ let parent =
+ LocalDefId { local_def_index: DefIndex::from_u32(self.ctxt_or_tag as u32) };
+ SpanData {
+ lo: BytePos(self.base_or_index),
+ hi: BytePos(self.base_or_index + len as u32),
+ ctxt: SyntaxContext::root(),
+ parent: Some(parent),
+ }
}
} else {
// Interned format.
@@ -141,8 +177,14 @@ impl Span {
pub fn ctxt(self) -> SyntaxContext {
let ctxt_or_tag = self.ctxt_or_tag as u32;
if ctxt_or_tag <= MAX_CTXT {
- // Inline format or interned format with inline ctxt.
- SyntaxContext::from_u32(ctxt_or_tag)
+ if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
+ // Inline format or interned format with inline ctxt.
+ SyntaxContext::from_u32(ctxt_or_tag)
+ } else {
+ // Inline format or interned format with inline parent.
+ // We know that the SyntaxContext is root.
+ SyntaxContext::root()
+ }
} else {
// Interned format.
let index = self.base_or_index;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9e446c96d..7597b8d12 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -9,7 +9,6 @@ use rustc_data_structures::sync::Lock;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::cmp::{Ord, PartialEq, PartialOrd};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str;
@@ -165,6 +164,7 @@ symbols! {
Capture,
Center,
Clone,
+ Context,
Continue,
Copy,
Count,
@@ -194,6 +194,7 @@ symbols! {
FromIterator,
FromResidual,
Future,
+ FutureOutput,
FxHashMap,
FxHashSet,
GlobalAlloc,
@@ -214,6 +215,7 @@ symbols! {
Is,
ItemContext,
Iterator,
+ IteratorItem,
Layout,
Left,
LinkedList,
@@ -377,9 +379,9 @@ symbols! {
assert_eq_macro,
assert_inhabited,
assert_macro,
+ assert_mem_uninitialized_valid,
assert_ne_macro,
assert_receiver_is_total_eq,
- assert_uninit_valid,
assert_zero_valid,
asserting,
associated_const_equality,
@@ -497,6 +499,7 @@ symbols! {
console,
const_allocate,
const_async_blocks,
+ const_closures,
const_compare_raw_pointers,
const_constructor,
const_deallocate,
@@ -612,6 +615,7 @@ symbols! {
dispatch_from_dyn,
div,
div_assign,
+ do_not_recommend,
doc,
doc_alias,
doc_auto_cfg,
@@ -829,6 +833,8 @@ symbols! {
item_like_imports,
iter,
iter_repeat,
+ iterator_collect_fn,
+ kcfi,
keyword,
kind,
kreg,
@@ -1040,6 +1046,7 @@ symbols! {
panic_2021,
panic_abort,
panic_bounds_check,
+ panic_cannot_unwind,
panic_display,
panic_fmt,
panic_handler,
@@ -1047,7 +1054,7 @@ symbols! {
panic_implementation,
panic_info,
panic_location,
- panic_no_unwind,
+ panic_nounwind,
panic_runtime,
panic_str,
panic_unwind,
@@ -1711,7 +1718,8 @@ impl fmt::Display for Ident {
}
}
-/// This is the most general way to print identifiers.
+/// The most general type to print identifiers.
+///
/// AST pretty-printer is used as a fallback for turning AST structures into token streams for
/// proc macros. Additionally, proc macros may stringify their input and expect it survive the
/// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
@@ -1800,7 +1808,7 @@ impl fmt::Display for MacroRulesNormalizedIdent {
pub struct Symbol(SymbolIndex);
rustc_index::newtype_index! {
- struct SymbolIndex { .. }
+ struct SymbolIndex {}
}
impl Symbol {
@@ -1974,7 +1982,6 @@ pub mod kw {
/// For example `sym::rustfmt` or `sym::u8`.
pub mod sym {
use super::Symbol;
- use std::convert::TryInto;
#[doc(inline)]
pub use super::sym_generated::*;