diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_span/Cargo.toml | 1 | ||||
-rw-r--r-- | compiler/rustc_span/src/def_id.rs | 20 | ||||
-rw-r--r-- | compiler/rustc_span/src/lib.rs | 14 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map.rs | 44 | ||||
-rw-r--r-- | compiler/rustc_span/src/source_map/tests.rs | 45 | ||||
-rw-r--r-- | compiler/rustc_span/src/span_encoding.rs | 42 | ||||
-rw-r--r-- | compiler/rustc_span/src/symbol.rs | 35 |
7 files changed, 167 insertions, 34 deletions
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 7227b193f..48a2ab0f9 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [lib] -doctest = false [dependencies] rustc_serialize = { path = "../rustc_serialize" } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 37b8371a8..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] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index da31b3462..322c7104b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -15,7 +15,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(if_let_guard)] #![feature(negative_impls)] #![feature(min_specialization)] @@ -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 } @@ -1637,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 4d94c92d3..f9566eeee 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -853,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; } @@ -908,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(); diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 3058ec45a..1fd81018f 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -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 ae4d1a463..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, @@ -210,6 +210,7 @@ symbols! { Implied, Input, Into, + IntoDiagnostic, IntoFuture, IntoIterator, IoRead, @@ -223,6 +224,7 @@ symbols! { Left, LinkedList, LintPass, + LocalKey, Mutex, MutexGuard, N, @@ -265,6 +267,7 @@ symbols! { Rc, Ready, Receiver, + RefCell, Relaxed, Release, Result, @@ -273,11 +276,11 @@ symbols! { Rust, RustcDecodable, RustcEncodable, + RwLock, RwLockReadGuard, RwLockWriteGuard, Send, SeqCst, - SessionDiagnostic, SliceIndex, Some, String, @@ -396,6 +399,7 @@ symbols! { assume_init, async_await, async_closure, + async_fn_in_trait, atomic, atomic_mod, atomics, @@ -447,6 +451,7 @@ symbols! { call_once, caller_location, capture_disjoint_fields, + cause, cdylib, ceilf32, ceilf64, @@ -781,6 +786,7 @@ symbols! { globs, gt, half_open_range_patterns, + half_open_range_patterns_in_slices, hash, hexagon_target_feature, hidden, @@ -990,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, @@ -1214,9 +1231,7 @@ symbols! { rust_eh_unregister_frames, rust_oom, rustc, - rustc_access_level, rustc_allocator, - rustc_allocator_nounwind, rustc_allocator_zeroed, rustc_allow_const_fn_unstable, rustc_allow_incoherent_impl, @@ -1242,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, @@ -1262,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, @@ -1281,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, @@ -1688,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()) } @@ -1703,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) } @@ -1881,6 +1901,13 @@ 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 { default fn encode(&self, s: &mut S) { s.emit_str(self.as_str()); |