diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
commit | 64d98f8ee037282c35007b64c2649055c56af1db (patch) | |
tree | 5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /compiler/rustc_span | |
parent | Adding debian version 1.67.1+dfsg1-1. (diff) | |
download | rustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz rustc-64d98f8ee037282c35007b64c2649055c56af1db.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.toml | 4 | ||||
-rw-r--r-- | compiler/rustc_span/src/analyze_source_file.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_span/src/def_id.rs | 16 | ||||
-rw-r--r-- | compiler/rustc_span/src/edition.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_span/src/hygiene.rs | 37 | ||||
-rw-r--r-- | compiler/rustc_span/src/lib.rs | 25 | ||||
-rw-r--r-- | compiler/rustc_span/src/profiling.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map.rs | 141 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map/tests.rs | 45 | ||||
-rw-r--r-- | compiler/rustc_span/src/span_encoding.rs | 86 | ||||
-rw-r--r-- | compiler/rustc_span/src/symbol.rs | 19 |
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::*; |