diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_span/src/def_id.rs | 35 | ||||
-rw-r--r-- | compiler/rustc_span/src/hygiene.rs | 29 | ||||
-rw-r--r-- | compiler/rustc_span/src/lib.rs | 49 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map.rs | 151 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map/tests.rs | 47 | ||||
-rw-r--r-- | compiler/rustc_span/src/span_encoding.rs | 42 | ||||
-rw-r--r-- | compiler/rustc_span/src/symbol.rs | 84 |
7 files changed, 277 insertions, 160 deletions
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index a1533fe46..bbeabdb55 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -218,7 +218,9 @@ impl<D: Decoder> Decodable<D> for DefIndex { /// index and a def index. /// /// You can create a `DefId` from a `LocalDefId` using `local_def_id.to_def_id()`. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)] +#[derive(Clone, PartialEq, Eq, Copy)] +// Don't derive order on 64-bit big-endian, so we can be consistent regardless of field order. +#[cfg_attr(not(all(target_pointer_width = "64", target_endian = "big")), derive(PartialOrd, Ord))] // On below-64 bit systems we can simply use the derived `Hash` impl #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))] #[repr(C)] @@ -260,6 +262,22 @@ impl Hash for DefId { } } +// Implement the same comparison as derived with the other field order. +#[cfg(all(target_pointer_width = "64", target_endian = "big"))] +impl Ord for DefId { + #[inline] + fn cmp(&self, other: &DefId) -> std::cmp::Ordering { + Ord::cmp(&(self.index, self.krate), &(other.index, other.krate)) + } +} +#[cfg(all(target_pointer_width = "64", target_endian = "big"))] +impl PartialOrd for DefId { + #[inline] + fn partial_cmp(&self, other: &DefId) -> Option<std::cmp::Ordering> { + Some(Ord::cmp(self, other)) + } +} + impl DefId { /// Makes a local `DefId` from the given `DefIndex`. #[inline] @@ -305,6 +323,12 @@ impl DefId { } } +impl From<LocalDefId> for DefId { + fn from(local: LocalDefId) -> DefId { + local.to_def_id() + } +} + impl<E: Encoder> Encodable<E> for DefId { default fn encode(&self, s: &mut E) { self.krate.encode(s); @@ -331,7 +355,7 @@ impl fmt::Debug for DefId { } } -rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId); +rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefIdMapEntry, DefId); /// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since /// we encode this information in the type, we can ensure at compile time that @@ -393,7 +417,12 @@ impl<D: Decoder> Decodable<D> for LocalDefId { } } -rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId); +rustc_data_structures::define_id_collections!( + LocalDefIdMap, + LocalDefIdSet, + LocalDefIdMapEntry, + LocalDefId +); impl<CTX: HashStableContext> HashStable<CTX> for DefId { #[inline] diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e169d3c7c..191186af6 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -41,7 +41,6 @@ use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::hash::Hash; -use tracing::*; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -945,12 +944,6 @@ pub struct ExpnData { /// internally without forcing the whole crate to opt-in /// to them. pub allow_internal_unstable: Option<Lrc<[Symbol]>>, - /// Whether the macro is allowed to use `unsafe` internally - /// even if the user crate has `#![forbid(unsafe_code)]`. - pub allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) - /// for a given macro. - pub local_inner_macros: bool, /// Edition of the crate in which the macro is defined. pub edition: Edition, /// The `DefId` of the macro being invoked, @@ -958,6 +951,13 @@ pub struct ExpnData { pub macro_def_id: Option<DefId>, /// The normal module (`mod`) in which the expanded macro was defined. pub parent_module: Option<DefId>, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other + /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? + pub collapse_debuginfo: bool, } impl !PartialEq for ExpnData {} @@ -970,11 +970,12 @@ impl ExpnData { call_site: Span, def_site: Span, allow_internal_unstable: Option<Lrc<[Symbol]>>, - allow_internal_unsafe: bool, - local_inner_macros: bool, edition: Edition, macro_def_id: Option<DefId>, parent_module: Option<DefId>, + allow_internal_unsafe: bool, + local_inner_macros: bool, + collapse_debuginfo: bool, ) -> ExpnData { ExpnData { kind, @@ -982,12 +983,13 @@ impl ExpnData { call_site, def_site, allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe, + local_inner_macros, + collapse_debuginfo, } } @@ -1005,12 +1007,13 @@ impl ExpnData { call_site, def_site: DUMMY_SP, allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe: false, + local_inner_macros: false, + collapse_debuginfo: false, } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index cf3069281..322c7104b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -15,11 +15,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] -#![feature(let_else)] #![feature(if_let_guard)] #![feature(negative_impls)] #![feature(min_specialization)] #![feature(rustc_attrs)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; @@ -74,8 +75,6 @@ use md5::Md5; use sha1::Sha1; use sha2::Sha256; -use tracing::debug; - #[cfg(test)] mod tests; @@ -299,7 +298,11 @@ impl From<PathBuf> for FileName { #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] pub enum FileNameDisplayPreference { + /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`. + /// This is appropriate for paths that get embedded into files produced by the compiler. Remapped, + /// 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, } @@ -533,9 +536,6 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn ctxt(self) -> SyntaxContext { - self.data_untracked().ctxt - } pub fn eq_ctxt(self, other: Span) -> bool { self.data_untracked().ctxt == other.data_untracked().ctxt } @@ -558,12 +558,25 @@ impl Span { self.data_untracked().is_dummy() } - /// Returns `true` if this span comes from a macro or desugaring. + /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { self.ctxt() != SyntaxContext::root() } + /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be + /// collapsed. + pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo + } + + /// Returns `true` if this span comes from MIR inlining. + pub fn is_inlined(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Inlined) + } + /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) @@ -662,6 +675,16 @@ impl Span { Some(self) } + /// Like `find_ancestor_inside`, but specifically for when spans might not + /// overlaps. Take care when using this, and prefer `find_ancestor_inside` + /// when you know that the spans are nested (modulo macro expansion). + pub fn find_ancestor_in_same_ctxt(mut self, other: Span) -> Option<Span> { + while !Span::eq_ctxt(self, other) { + self = self.parent_callsite()?; + } + Some(self) + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() @@ -1094,10 +1117,8 @@ pub enum ExternalSource { Unneeded, Foreign { kind: ExternalSourceKind, - /// This SourceFile's byte-offset within the source_map of its original crate. - original_start_pos: BytePos, - /// The end of this SourceFile within the source_map of its original crate. - original_end_pos: BytePos, + /// Index of the file inside metadata. + metadata_index: u32, }, } @@ -1616,11 +1637,7 @@ impl SourceFile { /// number. If the source_file is empty or the position is located before the /// first line, `None` is returned. pub fn lookup_line(&self, pos: BytePos) -> Option<usize> { - self.lines(|lines| match lines.binary_search(&pos) { - Ok(idx) => Some(idx), - Err(0) => None, - Err(idx) => Some(idx - 1), - }) + self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1)) } pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 28381157d..f9566eeee 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,7 +23,6 @@ use std::{convert::TryFrom, unreachable}; use std::fs; use std::io; -use tracing::debug; #[cfg(test)] mod tests; @@ -336,7 +335,7 @@ impl SourceMap { mut file_local_non_narrow_chars: Vec<NonNarrowChar>, mut file_local_normalized_pos: Vec<NormalizedPos>, original_start_pos: BytePos, - original_end_pos: BytePos, + metadata_index: u32, ) -> Lrc<SourceFile> { let start_pos = self .allocate_address_space(source_len) @@ -381,8 +380,7 @@ impl SourceMap { src_hash, external_src: Lock::new(ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, - original_start_pos, - original_end_pos, + metadata_index, }), start_pos, end_pos, @@ -473,7 +471,7 @@ impl SourceMap { let hi = self.lookup_char_pos(sp.hi()); let offset = self.lookup_char_pos(relative_to.lo()); - if lo.file.name != offset.file.name { + if lo.file.name != offset.file.name || !relative_to.contains(sp) { return self.span_to_embeddable_string(sp); } @@ -722,7 +720,7 @@ impl SourceMap { }) } - /// Extends the given `Span` to just after the next occurrence of `c`. + /// Extends the given `Span` to just before the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { let next_source = next_source.split(c).next().unwrap_or(""); @@ -855,28 +853,56 @@ impl SourceMap { } /// Returns a new span representing the next character after the end-point of this span. + /// Special cases: + /// - if span is a dummy one, returns the same span + /// - if next_point reached the end of source, return span with lo = hi + /// - respect multi-byte characters pub fn next_point(&self, sp: Span) -> Span { if sp.is_dummy() { return sp; } let start_of_next_point = sp.hi().0; - let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true); - // If the width is 1, then the next span should point to the same `lo` and `hi`. However, - // in the case of a multibyte character, where the width != 1, the next span should + let width = self.find_width_of_character_at_span(sp, true); + if width == 0 { + return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None); + } + // If the width is 1, then the next span should only contain the next char besides current ending. + // However, in the case of a multibyte character, where the width != 1, the next span should // span multiple bytes to include the whole character. let end_of_next_point = - start_of_next_point.checked_add(width - 1).unwrap_or(start_of_next_point); + start_of_next_point.checked_add(width).unwrap_or(start_of_next_point); - let end_of_next_point = BytePos(cmp::max(sp.lo().0 + 1, end_of_next_point)); + let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point)); Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) } + /// Returns a new span to check next none-whitespace character or some specified expected character + /// If `expect` is none, the first span of non-whitespace character is returned. + /// If `expect` presented, the first span of the character `expect` is returned + /// 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) { + sp = self.next_point(sp); + if let Ok(ref snippet) = self.span_to_snippet(sp) { + if expect.map_or(false, |es| snippet == es) { + break; + } + if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) { + break; + } + } + } + sp + } + /// Finds the width of the character, either before or after the end of provided span, /// depending on the `forwards` parameter. fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { let sp = sp.data(); - if sp.lo == sp.hi { + + if sp.lo == sp.hi && !forwards { debug!("find_width_of_character_at_span: early return empty span"); return 1; } @@ -910,9 +936,9 @@ impl SourceMap { 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); // Ensure indexes are also not malformed. - if start_index > end_index || end_index > source_len { + if start_index > end_index || end_index > source_len - 1 { debug!("find_width_of_character_at_span: source indexes are malformed"); - return 1; + return 0; } let src = local_begin.sf.external_src.borrow(); @@ -983,93 +1009,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function<T>` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool { source_file.add_external_src(|| { match source_file.name { @@ -1148,13 +1087,13 @@ impl FilePathMapping { return remap_path_prefix(&self.mapping, path); - #[instrument(level = "debug", skip(mapping))] + #[instrument(level = "debug", skip(mapping), ret)] fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, 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() { - debug!("Trying to apply {:?} => {:?}", from, to); + debug!("Trying to apply {from:?} => {to:?}"); if let Ok(rest) = path.strip_prefix(from) { let remapped = if rest.as_os_str().is_empty() { @@ -1168,15 +1107,15 @@ impl FilePathMapping { } else { to.join(rest) }; - debug!("Match - remapped {:?} => {:?}", path, remapped); + debug!("Match - remapped"); return (remapped, true); } else { - debug!("No match - prefix {:?} does not match {:?}", from, path); + debug!("No match - prefix {from:?} does not match"); } } - debug!("Path {:?} was not remapped", path); + debug!("not remapped"); (path, false) } } diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index be827cea8..1fd81018f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -251,7 +251,7 @@ fn t10() { non_narrow_chars, normalized_pos, start_pos, - end_pos, + 0, ); assert!( @@ -479,3 +479,48 @@ fn path_prefix_remapping_expand_to_absolute() { RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.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()); + + // Dummy spans don't advance. + let span = DUMMY_SP; + let span = sm.next_point(span); + assert_eq!(span.lo().0, 0); + assert_eq!(span.hi().0, 0); + + // Span advance respect multi-byte character + let span = Span::with_root_ctxt(BytePos(0), BytePos(1)); + assert_eq!(sm.span_to_snippet(span), Ok("a".to_string())); + let span = sm.next_point(span); + assert_eq!(sm.span_to_snippet(span), Ok("…".to_string())); + assert_eq!(span.lo().0, 1); + assert_eq!(span.hi().0, 4); + + // An empty span pointing just before a multi-byte character should + // advance to contain the multi-byte character. + let span = Span::with_root_ctxt(BytePos(1), BytePos(1)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 1); + assert_eq!(span.hi().0, 4); + + let span = Span::with_root_ctxt(BytePos(1), BytePos(4)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 4); + assert_eq!(span.hi().0, 5); + + // A non-empty span at the last byte should advance to create an empty + // span pointing at the end of the file. + let span = Span::with_root_ctxt(BytePos(4), BytePos(5)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 5); + assert_eq!(span.hi().0, 5); + + // Empty span pointing just past the last byte. + let span = Span::with_root_ctxt(BytePos(5), BytePos(5)); + let span = sm.next_point(span); + assert_eq!(span.lo().0, 5); + assert_eq!(span.hi().0, 5); +} diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 3ee329e97..b3de67415 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -28,12 +28,17 @@ use rustc_data_structures::fx::FxIndexSet; /// Inline (compressed) format: /// - `span.base_or_index == span_data.lo` /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) -/// - `span.ctxt == span_data.ctxt` (must be `<= MAX_CTXT`) +/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`) +/// +/// Interned format with inline `SyntaxContext`: +/// - `span.base_or_index == index` (indexes into the interner table) +/// - `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`) /// /// 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) -/// - `span.ctxt == 0` +/// - `span.ctxt_or_tag == CTXT_TAG` /// /// The inline form uses 0 for the tag value (rather than 1) so that we don't /// need to mask out the tag bit when getting the length, and so that the @@ -50,10 +55,10 @@ use rustc_data_structures::fx::FxIndexSet; /// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough /// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur /// dozens of times in a typical crate. -/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that +/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that /// large `ctxt` values will cause interning. The number of bits needed for /// `ctxt` values depend partly on the crate size and partly on the form of -/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`, +/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`, /// but larger crates might need more than 16 bits. /// /// In order to reliably use parented spans in incremental compilation, @@ -65,15 +70,16 @@ use rustc_data_structures::fx::FxIndexSet; pub struct Span { base_or_index: u32, len_or_tag: u16, - ctxt_or_zero: u16, + ctxt_or_tag: u16, } const LEN_TAG: u16 = 0b1000_0000_0000_0000; const MAX_LEN: u32 = 0b0111_1111_1111_1111; -const MAX_CTXT: u32 = 0b1111_1111_1111_1111; +const CTXT_TAG: u32 = 0b1111_1111_1111_1111; +const MAX_CTXT: u32 = CTXT_TAG - 1; /// Dummy span, both position and length are zero, syntax context is zero as well. -pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_zero: 0 }; +pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 }; impl Span { #[inline] @@ -91,12 +97,13 @@ impl Span { 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_zero: ctxt2 as u16 } + 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 })); - Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 } + 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 } } } @@ -119,16 +126,29 @@ impl Span { 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_zero as u32), + ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32), parent: None, } } else { // Interned format. - debug_assert!(self.ctxt_or_zero == 0); let index = self.base_or_index; with_span_interner(|interner| interner.spans[index as usize]) } } + + /// This function is used as a fast path when decoding the full `SpanData` is not necessary. + #[inline] + 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) + } else { + // Interned format. + let index = self.base_or_index; + with_span_interner(|interner| interner.spans[index as usize].ctxt) + } + } } #[derive(Default)] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 791160ff6..7f16da52b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -125,7 +125,7 @@ symbols! { Symbols { AcqRel, Acquire, - AddSubdiagnostic, + AddToDiagnostic, Alignment, Any, Arc, @@ -157,6 +157,7 @@ symbols! { BTreeSet, BinaryHeap, Borrow, + BorrowMut, Break, C, CStr, @@ -209,10 +210,12 @@ symbols! { Implied, Input, Into, + IntoDiagnostic, IntoFuture, IntoIterator, IoRead, IoWrite, + IpAddr, IrTyKind, Is, ItemContext, @@ -221,7 +224,9 @@ symbols! { Left, LinkedList, LintPass, + LocalKey, Mutex, + MutexGuard, N, NonZeroI128, NonZeroI16, @@ -262,6 +267,7 @@ symbols! { Rc, Ready, Receiver, + RefCell, Relaxed, Release, Result, @@ -270,9 +276,11 @@ symbols! { Rust, RustcDecodable, RustcEncodable, + RwLock, + RwLockReadGuard, + RwLockWriteGuard, Send, SeqCst, - SessionDiagnostic, SliceIndex, Some, String, @@ -280,6 +288,7 @@ symbols! { StructuralPartialEq, SubdiagnosticMessage, Sync, + T, Target, ToOwned, ToString, @@ -334,6 +343,7 @@ symbols! { alias, align, align_offset, + alignment, alignstack, all, alloc, @@ -389,6 +399,7 @@ symbols! { assume_init, async_await, async_closure, + async_fn_in_trait, atomic, atomic_mod, atomics, @@ -440,6 +451,7 @@ symbols! { call_once, caller_location, capture_disjoint_fields, + cause, cdylib, ceilf32, ceilf64, @@ -481,6 +493,7 @@ symbols! { cmse_nonsecure_entry, coerce_unsized, cold, + collapse_debuginfo, column, column_macro, compare_and_swap, @@ -504,7 +517,6 @@ symbols! { const_deallocate, const_eval_limit, const_eval_select, - const_eval_select_ct, const_evaluatable_checked, const_extern_fn, const_fn, @@ -644,6 +656,7 @@ symbols! { dropck_parametricity, dylib, dyn_metadata, + dyn_star, dyn_trait, e, edition_macro_pats, @@ -656,7 +669,6 @@ symbols! { emit_struct, emit_struct_field, enable, - enclosing_scope, encode, end, env, @@ -759,7 +771,7 @@ symbols! { gen_future, gen_kill, generator, - generator_return, + generator_clone, generator_state, generators, generic_arg_infer, @@ -774,6 +786,7 @@ symbols! { globs, gt, half_open_range_patterns, + half_open_range_patterns_in_slices, hash, hexagon_target_feature, hidden, @@ -802,6 +815,7 @@ symbols! { impl_trait_in_bindings, implied_by, import, + import_name_type, import_shadowing, imported_main, in_band_lifetimes, @@ -817,6 +831,7 @@ symbols! { infer_outlives_requirements, infer_static_outlives_requirements, inherent_associated_types, + inherit, inlateout, inline, inline_const, @@ -859,6 +874,7 @@ symbols! { lib, libc, lifetime, + lifetimes, likely, line, line_macro, @@ -980,7 +996,18 @@ symbols! { never_type, never_type_fallback, new, + new_binary, + new_debug, + new_display, + new_lower_exp, + new_lower_hex, + new_octal, + new_pointer, new_unchecked, + new_upper_exp, + new_upper_hex, + new_v1, + new_v1_formatted, next, nll, no, @@ -1056,6 +1083,7 @@ symbols! { panic_unwind, panicking, param_attrs, + parent_label, partial_cmp, partial_ord, passes, @@ -1110,14 +1138,15 @@ symbols! { profiler_builtins, profiler_runtime, ptr, - ptr_guaranteed_eq, - ptr_guaranteed_ne, + ptr_guaranteed_cmp, + ptr_mask, ptr_null, ptr_null_mut, ptr_offset_from, ptr_offset_from_unsigned, pub_macro_rules, pub_restricted, + public, pure, pushpop_unsafe, qreg, @@ -1170,8 +1199,10 @@ symbols! { repr_packed, repr_simd, repr_transparent, + require, residual, result, + return_position_impl_trait_in_trait, rhs, rintf32, rintf64, @@ -1201,7 +1232,6 @@ symbols! { rust_oom, rustc, rustc_allocator, - rustc_allocator_nounwind, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, @@ -1217,6 +1247,7 @@ symbols! { rustc_conversion_suggestion, rustc_deallocator, rustc_def_path, + rustc_default_body_unstable, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, @@ -1226,6 +1257,7 @@ symbols! { rustc_dump_program_clauses, rustc_dump_user_substs, rustc_dump_vtable, + rustc_effective_visibility, rustc_error, rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, @@ -1246,6 +1278,7 @@ symbols! { rustc_mir, rustc_must_implement_one_of, rustc_nonnull_optimization_guaranteed, + rustc_nounwind, rustc_object_lifetime_default, rustc_on_unimplemented, rustc_outlives, @@ -1265,6 +1298,7 @@ symbols! { rustc_reallocator, rustc_regions, rustc_reservation_impl, + rustc_safe_intrinsic, rustc_serialize, rustc_skip_array_during_method_dispatch, rustc_specialization_trait, @@ -1279,9 +1313,11 @@ symbols! { rustc_variance, rustdoc, rustdoc_internals, + rustdoc_missing_doc_code_examples, rustfmt, rvalue_static_promotion, s, + safety, sanitize, sanitizer_runtime, saturating_add, @@ -1295,6 +1331,8 @@ symbols! { should_panic, shr, shr_assign, + sig_dfl, + sig_ign, simd, simd_add, simd_and, @@ -1302,9 +1340,11 @@ symbols! { simd_as, simd_bitmask, simd_cast, + simd_cast_ptr, simd_ceil, simd_div, simd_eq, + simd_expose_addr, simd_extract, simd_fabs, simd_fcos, @@ -1320,6 +1360,7 @@ symbols! { simd_fmin, simd_fpow, simd_fpowi, + simd_from_exposed_addr, simd_fsin, simd_fsqrt, simd_gather, @@ -1464,6 +1505,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_opts, transmute_trait, transparent, transparent_enums, @@ -1480,6 +1522,7 @@ symbols! { tuple, tuple_from_req, tuple_indexing, + tuple_trait, two_phase, ty, type_alias_enum_variants, @@ -1513,6 +1556,7 @@ symbols! { unit, universal_impl_trait, unix, + unix_sigpipe, unlikely, unmarked_api, unpin, @@ -1558,6 +1602,7 @@ symbols! { va_list, va_start, val, + validity, values, var, variant_count, @@ -1661,6 +1706,7 @@ impl Ident { /// macro (e.g., `macro` or `macro_rules!` items) and stay different if they came from different /// non-transparent macros. /// Technically, this operation strips all transparent marks from ident's syntactic context. + #[inline] pub fn normalize_to_macro_rules(self) -> Ident { Ident::new(self.name, self.span.normalize_to_macro_rules()) } @@ -1676,6 +1722,7 @@ impl Ident { } impl PartialEq for Ident { + #[inline] fn eq(&self, rhs: &Self) -> bool { self.name == rhs.name && self.span.eq_ctxt(rhs.span) } @@ -1801,6 +1848,11 @@ impl Symbol { Symbol(SymbolIndex::from_u32(n)) } + /// for use in Decoder only + pub fn new_from_decoded(n: u32) -> Self { + Self::new(n) + } + /// Maps a string to its interned representation. pub fn intern(string: &str) -> Self { with_session_globals(|session_globals| session_globals.symbol_interner.intern(string)) @@ -1849,15 +1901,22 @@ impl fmt::Display for Symbol { } } +// takes advantage of `str::to_string` specialization +impl ToString for Symbol { + fn to_string(&self) -> String { + self.as_str().to_string() + } +} + impl<S: Encoder> Encodable<S> for Symbol { - fn encode(&self, s: &mut S) { + default fn encode(&self, s: &mut S) { s.emit_str(self.as_str()); } } impl<D: Decoder> Decodable<D> for Symbol { #[inline] - fn decode(d: &mut D) -> Symbol { + default fn decode(d: &mut D) -> Symbol { Symbol::intern(&d.read_str()) } } @@ -2025,6 +2084,11 @@ impl Symbol { pub fn can_be_raw(self) -> bool { self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword() } + + /// Is this symbol was interned in compiler's `symbols!` macro + pub fn is_preinterned(self) -> bool { + self.as_u32() < PREINTERNED_SYMBOLS_COUNT + } } impl Ident { |