summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_span
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_span/Cargo.toml1
-rw-r--r--compiler/rustc_span/src/def_id.rs20
-rw-r--r--compiler/rustc_span/src/lib.rs14
-rw-r--r--compiler/rustc_span/src/source_map.rs44
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs45
-rw-r--r--compiler/rustc_span/src/span_encoding.rs42
-rw-r--r--compiler/rustc_span/src/symbol.rs35
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());