Auto merge of #115418 - Zoxc:freeze-source, r=oli-obk
Use `Freeze` for `SourceFile` This uses the `Freeze` type in `SourceFile` to let accessing `external_src` and `lines` be lock-free. Behavior of `add_external_src` is changed to set `ExternalSourceKind::AbsentErr` on a hash mismatch which matches the documentation. `ExternalSourceKind::Unneeded` was removed as it's unused. Based on https://github.com/rust-lang/rust/pull/115401.
This commit is contained in:
commit
26f4b72724
16 changed files with 294 additions and 225 deletions
|
@ -81,7 +81,7 @@ impl DebugContext {
|
||||||
|
|
||||||
match tcx.sess.source_map().lookup_line(span.lo()) {
|
match tcx.sess.source_map().lookup_line(span.lo()) {
|
||||||
Ok(SourceFileAndLine { sf: file, line }) => {
|
Ok(SourceFileAndLine { sf: file, line }) => {
|
||||||
let line_pos = file.lines(|lines| lines[line]);
|
let line_pos = file.lines()[line];
|
||||||
let col = file.relative_position(span.lo()) - line_pos;
|
let col = file.relative_position(span.lo()) - line_pos;
|
||||||
|
|
||||||
(file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1)
|
(file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1)
|
||||||
|
|
|
@ -263,7 +263,7 @@ impl CodegenCx<'_, '_> {
|
||||||
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
|
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
|
||||||
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
|
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
|
||||||
Ok(SourceFileAndLine { sf: file, line }) => {
|
Ok(SourceFileAndLine { sf: file, line }) => {
|
||||||
let line_pos = file.lines(|lines| lines[line]);
|
let line_pos = file.lines()[line];
|
||||||
|
|
||||||
// Use 1-based indexing.
|
// Use 1-based indexing.
|
||||||
let line = (line + 1) as u32;
|
let line = (line + 1) as u32;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::sync::{AtomicBool, ReadGuard, RwLock, WriteGuard};
|
||||||
use crate::sync::{DynSend, DynSync};
|
use crate::sync::{DynSend, DynSync};
|
||||||
use std::{
|
use std::{
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
|
intrinsics::likely,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::atomic::Ordering,
|
sync::atomic::Ordering,
|
||||||
|
@ -27,7 +28,47 @@ unsafe impl<T: DynSync + DynSend> DynSync for FreezeLock<T> {}
|
||||||
impl<T> FreezeLock<T> {
|
impl<T> FreezeLock<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(value: T) -> Self {
|
pub fn new(value: T) -> Self {
|
||||||
Self { data: UnsafeCell::new(value), frozen: AtomicBool::new(false), lock: RwLock::new(()) }
|
Self::with(value, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn frozen(value: T) -> Self {
|
||||||
|
Self::with(value, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with(value: T, frozen: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
data: UnsafeCell::new(value),
|
||||||
|
frozen: AtomicBool::new(frozen),
|
||||||
|
lock: RwLock::new(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clones the inner value along with the frozen state.
|
||||||
|
#[inline]
|
||||||
|
pub fn clone(&self) -> Self
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
let lock = self.read();
|
||||||
|
Self::with(lock.clone(), self.is_frozen())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_frozen(&self) -> bool {
|
||||||
|
self.frozen.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the inner value if frozen.
|
||||||
|
#[inline]
|
||||||
|
pub fn get(&self) -> Option<&T> {
|
||||||
|
if likely(self.frozen.load(Ordering::Acquire)) {
|
||||||
|
// SAFETY: This is frozen so the data cannot be modified.
|
||||||
|
unsafe { Some(&*self.data.get()) }
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -42,13 +83,26 @@ impl<T> FreezeLock<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn borrow(&self) -> FreezeReadGuard<'_, T> {
|
||||||
|
self.read()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn write(&self) -> FreezeWriteGuard<'_, T> {
|
pub fn write(&self) -> FreezeWriteGuard<'_, T> {
|
||||||
|
self.try_write().expect("still mutable")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn try_write(&self) -> Option<FreezeWriteGuard<'_, T>> {
|
||||||
let _lock_guard = self.lock.write();
|
let _lock_guard = self.lock.write();
|
||||||
// Use relaxed ordering since we're in the write lock.
|
// Use relaxed ordering since we're in the write lock.
|
||||||
assert!(!self.frozen.load(Ordering::Relaxed), "still mutable");
|
if self.frozen.load(Ordering::Relaxed) {
|
||||||
FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData }
|
None
|
||||||
|
} else {
|
||||||
|
Some(FreezeWriteGuard { _lock_guard, lock: self, marker: PhantomData })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -90,6 +144,15 @@ pub struct FreezeWriteGuard<'a, T> {
|
||||||
marker: PhantomData<&'a mut T>,
|
marker: PhantomData<&'a mut T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T> FreezeWriteGuard<'a, T> {
|
||||||
|
pub fn freeze(self) -> &'a T {
|
||||||
|
self.lock.frozen.store(true, Ordering::Release);
|
||||||
|
|
||||||
|
// SAFETY: This is frozen so the data cannot be modified and shared access is sound.
|
||||||
|
unsafe { &*self.lock.data.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> {
|
impl<'a, T: 'a> Deref for FreezeWriteGuard<'a, T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -169,7 +169,7 @@ impl AnnotateSnippetEmitterWriter {
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
// Ensure the source file is present before we try
|
// Ensure the source file is present before we try
|
||||||
// to load a string from it.
|
// to load a string from it.
|
||||||
source_map.ensure_source_file_source_present(file.clone());
|
source_map.ensure_source_file_source_present(&file);
|
||||||
(
|
(
|
||||||
format!("{}", source_map.filename_for_diagnostics(&file.name)),
|
format!("{}", source_map.filename_for_diagnostics(&file.name)),
|
||||||
source_string(file.clone(), &line),
|
source_string(file.clone(), &line),
|
||||||
|
|
|
@ -1193,7 +1193,7 @@ impl EmitterWriter {
|
||||||
let will_be_emitted = |span: Span| {
|
let will_be_emitted = |span: Span| {
|
||||||
!span.is_dummy() && {
|
!span.is_dummy() && {
|
||||||
let file = sm.lookup_source_file(span.hi());
|
let file = sm.lookup_source_file(span.hi());
|
||||||
sm.ensure_source_file_source_present(file)
|
sm.ensure_source_file_source_present(&file)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1388,7 +1388,7 @@ impl EmitterWriter {
|
||||||
// Print out the annotate source lines that correspond with the error
|
// Print out the annotate source lines that correspond with the error
|
||||||
for annotated_file in annotated_files {
|
for annotated_file in annotated_files {
|
||||||
// we can't annotate anything if the source is unavailable.
|
// we can't annotate anything if the source is unavailable.
|
||||||
if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
|
if !sm.ensure_source_file_source_present(&annotated_file.file) {
|
||||||
if !self.short_message {
|
if !self.short_message {
|
||||||
// We'll just print an unannotated message.
|
// We'll just print an unannotated message.
|
||||||
for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
|
for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
|
||||||
|
|
|
@ -558,7 +558,7 @@ impl DiagnosticSpanLine {
|
||||||
.span_to_lines(span)
|
.span_to_lines(span)
|
||||||
.map(|lines| {
|
.map(|lines| {
|
||||||
// We can't get any lines if the source is unavailable.
|
// We can't get any lines if the source is unavailable.
|
||||||
if !je.sm.ensure_source_file_source_present(lines.file.clone()) {
|
if !je.sm.ensure_source_file_source_present(&lines.file) {
|
||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ impl CodeSuggestion {
|
||||||
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
|
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
|
||||||
|
|
||||||
// We can't splice anything if the source is unavailable.
|
// We can't splice anything if the source is unavailable.
|
||||||
if !sm.ensure_source_file_source_present(lines.file.clone()) {
|
if !sm.ensure_source_file_source_present(&lines.file) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,8 +280,8 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
|
||||||
// All of this logic ensures that the final result of deserialization is a 'normal'
|
// All of this logic ensures that the final result of deserialization is a 'normal'
|
||||||
// Span that can be used without any additional trouble.
|
// Span that can be used without any additional trouble.
|
||||||
let metadata_index = {
|
let metadata_index = {
|
||||||
// Introduce a new scope so that we drop the 'lock()' temporary
|
// Introduce a new scope so that we drop the 'read()' temporary
|
||||||
match &*source_file.external_src.lock() {
|
match &*source_file.external_src.read() {
|
||||||
ExternalSource::Foreign { metadata_index, .. } => *metadata_index,
|
ExternalSource::Foreign { metadata_index, .. } => *metadata_index,
|
||||||
src => panic!("Unexpected external source {src:?}"),
|
src => panic!("Unexpected external source {src:?}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -692,7 +692,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
|
||||||
let len = BytePos::decode(decoder);
|
let len = BytePos::decode(decoder);
|
||||||
|
|
||||||
let file_lo = decoder.file_index_to_file(file_lo_index);
|
let file_lo = decoder.file_index_to_file(file_lo_index);
|
||||||
let lo = file_lo.lines(|lines| lines[line_lo - 1] + col_lo);
|
let lo = file_lo.lines()[line_lo - 1] + col_lo;
|
||||||
let lo = file_lo.absolute_position(lo);
|
let lo = file_lo.absolute_position(lo);
|
||||||
let hi = lo + len;
|
let hi = lo + len;
|
||||||
|
|
||||||
|
|
|
@ -79,15 +79,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
|
||||||
|
|
||||||
src_hash.hash_stable(hcx, hasher);
|
src_hash.hash_stable(hcx, hasher);
|
||||||
|
|
||||||
// We are always in `Lines` form by the time we reach here.
|
{
|
||||||
assert!(self.lines.borrow().is_lines());
|
// We are always in `Lines` form by the time we reach here.
|
||||||
self.lines(|lines| {
|
assert!(self.lines.read().is_lines());
|
||||||
|
let lines = self.lines();
|
||||||
// We only hash the relative position within this source_file
|
// We only hash the relative position within this source_file
|
||||||
lines.len().hash_stable(hcx, hasher);
|
lines.len().hash_stable(hcx, hasher);
|
||||||
for &line in lines.iter() {
|
for &line in lines.iter() {
|
||||||
line.hash_stable(hcx, hasher);
|
line.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// We only hash the relative position within this source_file
|
// We only hash the relative position within this source_file
|
||||||
multibyte_chars.len().hash_stable(hcx, hasher);
|
multibyte_chars.len().hash_stable(hcx, hasher);
|
||||||
|
|
|
@ -33,7 +33,7 @@ extern crate rustc_macros;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate tracing;
|
extern crate tracing;
|
||||||
|
|
||||||
use rustc_data_structures::AtomicRef;
|
use rustc_data_structures::{cold_path, AtomicRef};
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ pub mod fatal_error;
|
||||||
pub mod profiling;
|
pub mod profiling;
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
|
use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
|
||||||
use rustc_data_structures::sync::{Lock, Lrc};
|
use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::{self, Ordering};
|
use std::cmp::{self, Ordering};
|
||||||
|
@ -1206,7 +1206,6 @@ pub enum ExternalSourceKind {
|
||||||
AbsentOk,
|
AbsentOk,
|
||||||
/// A failed attempt has been made to load the external source.
|
/// A failed attempt has been made to load the external source.
|
||||||
AbsentErr,
|
AbsentErr,
|
||||||
Unneeded,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalSource {
|
impl ExternalSource {
|
||||||
|
@ -1343,13 +1342,13 @@ pub struct SourceFile {
|
||||||
pub src_hash: SourceFileHash,
|
pub src_hash: SourceFileHash,
|
||||||
/// The external source code (used for external crates, which will have a `None`
|
/// The external source code (used for external crates, which will have a `None`
|
||||||
/// value as `self.src`.
|
/// value as `self.src`.
|
||||||
pub external_src: Lock<ExternalSource>,
|
pub external_src: FreezeLock<ExternalSource>,
|
||||||
/// The start position of this source in the `SourceMap`.
|
/// The start position of this source in the `SourceMap`.
|
||||||
pub start_pos: BytePos,
|
pub start_pos: BytePos,
|
||||||
/// The byte length of this source.
|
/// The byte length of this source.
|
||||||
pub source_len: RelativeBytePos,
|
pub source_len: RelativeBytePos,
|
||||||
/// Locations of lines beginnings in the source code.
|
/// Locations of lines beginnings in the source code.
|
||||||
pub lines: Lock<SourceFileLines>,
|
pub lines: FreezeLock<SourceFileLines>,
|
||||||
/// Locations of multi-byte characters in the source code.
|
/// Locations of multi-byte characters in the source code.
|
||||||
pub multibyte_chars: Vec<MultiByteChar>,
|
pub multibyte_chars: Vec<MultiByteChar>,
|
||||||
/// Width of characters that are not narrow in the source code.
|
/// Width of characters that are not narrow in the source code.
|
||||||
|
@ -1368,10 +1367,10 @@ impl Clone for SourceFile {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
src: self.src.clone(),
|
src: self.src.clone(),
|
||||||
src_hash: self.src_hash,
|
src_hash: self.src_hash,
|
||||||
external_src: Lock::new(self.external_src.borrow().clone()),
|
external_src: self.external_src.clone(),
|
||||||
start_pos: self.start_pos,
|
start_pos: self.start_pos,
|
||||||
source_len: self.source_len,
|
source_len: self.source_len,
|
||||||
lines: Lock::new(self.lines.borrow().clone()),
|
lines: self.lines.clone(),
|
||||||
multibyte_chars: self.multibyte_chars.clone(),
|
multibyte_chars: self.multibyte_chars.clone(),
|
||||||
non_narrow_chars: self.non_narrow_chars.clone(),
|
non_narrow_chars: self.non_narrow_chars.clone(),
|
||||||
normalized_pos: self.normalized_pos.clone(),
|
normalized_pos: self.normalized_pos.clone(),
|
||||||
|
@ -1389,64 +1388,63 @@ impl<S: Encoder> Encodable<S> for SourceFile {
|
||||||
self.source_len.encode(s);
|
self.source_len.encode(s);
|
||||||
|
|
||||||
// We are always in `Lines` form by the time we reach here.
|
// We are always in `Lines` form by the time we reach here.
|
||||||
assert!(self.lines.borrow().is_lines());
|
assert!(self.lines.read().is_lines());
|
||||||
self.lines(|lines| {
|
let lines = self.lines();
|
||||||
// Store the length.
|
// Store the length.
|
||||||
s.emit_u32(lines.len() as u32);
|
s.emit_u32(lines.len() as u32);
|
||||||
|
|
||||||
// Compute and store the difference list.
|
// Compute and store the difference list.
|
||||||
if lines.len() != 0 {
|
if lines.len() != 0 {
|
||||||
let max_line_length = if lines.len() == 1 {
|
let max_line_length = if lines.len() == 1 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
lines
|
lines
|
||||||
.array_windows()
|
.array_windows()
|
||||||
.map(|&[fst, snd]| snd - fst)
|
.map(|&[fst, snd]| snd - fst)
|
||||||
.map(|bp| bp.to_usize())
|
.map(|bp| bp.to_usize())
|
||||||
.max()
|
.max()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes_per_diff: usize = match max_line_length {
|
let bytes_per_diff: usize = match max_line_length {
|
||||||
0..=0xFF => 1,
|
0..=0xFF => 1,
|
||||||
0x100..=0xFFFF => 2,
|
0x100..=0xFFFF => 2,
|
||||||
_ => 4,
|
_ => 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Encode the number of bytes used per diff.
|
// Encode the number of bytes used per diff.
|
||||||
s.emit_u8(bytes_per_diff as u8);
|
s.emit_u8(bytes_per_diff as u8);
|
||||||
|
|
||||||
// Encode the first element.
|
// Encode the first element.
|
||||||
assert_eq!(lines[0], RelativeBytePos(0));
|
assert_eq!(lines[0], RelativeBytePos(0));
|
||||||
|
|
||||||
// Encode the difference list.
|
// Encode the difference list.
|
||||||
let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
|
let diff_iter = lines.array_windows().map(|&[fst, snd]| snd - fst);
|
||||||
let num_diffs = lines.len() - 1;
|
let num_diffs = lines.len() - 1;
|
||||||
let mut raw_diffs;
|
let mut raw_diffs;
|
||||||
match bytes_per_diff {
|
match bytes_per_diff {
|
||||||
1 => {
|
1 => {
|
||||||
raw_diffs = Vec::with_capacity(num_diffs);
|
raw_diffs = Vec::with_capacity(num_diffs);
|
||||||
for diff in diff_iter {
|
for diff in diff_iter {
|
||||||
raw_diffs.push(diff.0 as u8);
|
raw_diffs.push(diff.0 as u8);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
2 => {
|
|
||||||
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
|
||||||
for diff in diff_iter {
|
|
||||||
raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
4 => {
|
|
||||||
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
|
||||||
for diff in diff_iter {
|
|
||||||
raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
s.emit_raw_bytes(&raw_diffs);
|
2 => {
|
||||||
|
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
||||||
|
for diff in diff_iter {
|
||||||
|
raw_diffs.extend_from_slice(&(diff.0 as u16).to_le_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
raw_diffs = Vec::with_capacity(bytes_per_diff * num_diffs);
|
||||||
|
for diff in diff_iter {
|
||||||
|
raw_diffs.extend_from_slice(&(diff.0).to_le_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
});
|
s.emit_raw_bytes(&raw_diffs);
|
||||||
|
}
|
||||||
|
|
||||||
self.multibyte_chars.encode(s);
|
self.multibyte_chars.encode(s);
|
||||||
self.non_narrow_chars.encode(s);
|
self.non_narrow_chars.encode(s);
|
||||||
|
@ -1488,8 +1486,8 @@ impl<D: Decoder> Decodable<D> for SourceFile {
|
||||||
src_hash,
|
src_hash,
|
||||||
// Unused - the metadata decoder will construct
|
// Unused - the metadata decoder will construct
|
||||||
// a new SourceFile, filling in `external_src` properly
|
// a new SourceFile, filling in `external_src` properly
|
||||||
external_src: Lock::new(ExternalSource::Unneeded),
|
external_src: FreezeLock::frozen(ExternalSource::Unneeded),
|
||||||
lines: Lock::new(lines),
|
lines: FreezeLock::new(lines),
|
||||||
multibyte_chars,
|
multibyte_chars,
|
||||||
non_narrow_chars,
|
non_narrow_chars,
|
||||||
normalized_pos,
|
normalized_pos,
|
||||||
|
@ -1530,10 +1528,10 @@ impl SourceFile {
|
||||||
name,
|
name,
|
||||||
src: Some(Lrc::new(src)),
|
src: Some(Lrc::new(src)),
|
||||||
src_hash,
|
src_hash,
|
||||||
external_src: Lock::new(ExternalSource::Unneeded),
|
external_src: FreezeLock::frozen(ExternalSource::Unneeded),
|
||||||
start_pos: BytePos::from_u32(0),
|
start_pos: BytePos::from_u32(0),
|
||||||
source_len: RelativeBytePos::from_u32(source_len),
|
source_len: RelativeBytePos::from_u32(source_len),
|
||||||
lines: Lock::new(SourceFileLines::Lines(lines)),
|
lines: FreezeLock::frozen(SourceFileLines::Lines(lines)),
|
||||||
multibyte_chars,
|
multibyte_chars,
|
||||||
non_narrow_chars,
|
non_narrow_chars,
|
||||||
normalized_pos,
|
normalized_pos,
|
||||||
|
@ -1542,65 +1540,82 @@ impl SourceFile {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lines<F, R>(&self, f: F) -> R
|
/// This converts the `lines` field to contain `SourceFileLines::Lines` if needed and freezes it.
|
||||||
where
|
fn convert_diffs_to_lines_frozen(&self) {
|
||||||
F: FnOnce(&[RelativeBytePos]) -> R,
|
let mut guard = if let Some(guard) = self.lines.try_write() { guard } else { return };
|
||||||
{
|
|
||||||
let mut guard = self.lines.borrow_mut();
|
|
||||||
match &*guard {
|
|
||||||
SourceFileLines::Lines(lines) => f(lines),
|
|
||||||
SourceFileLines::Diffs(SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs }) => {
|
|
||||||
// Convert from "diffs" form to "lines" form.
|
|
||||||
let num_lines = num_diffs + 1;
|
|
||||||
let mut lines = Vec::with_capacity(num_lines);
|
|
||||||
let mut line_start = RelativeBytePos(0);
|
|
||||||
lines.push(line_start);
|
|
||||||
|
|
||||||
assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
|
let SourceFileDiffs { bytes_per_diff, num_diffs, raw_diffs } = match &*guard {
|
||||||
match bytes_per_diff {
|
SourceFileLines::Diffs(diffs) => diffs,
|
||||||
1 => {
|
SourceFileLines::Lines(..) => {
|
||||||
lines.extend(raw_diffs.into_iter().map(|&diff| {
|
FreezeWriteGuard::freeze(guard);
|
||||||
line_start = line_start + RelativeBytePos(diff as u32);
|
return;
|
||||||
line_start
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
lines.extend((0..*num_diffs).map(|i| {
|
|
||||||
let pos = bytes_per_diff * i;
|
|
||||||
let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
|
|
||||||
let diff = u16::from_le_bytes(bytes);
|
|
||||||
line_start = line_start + RelativeBytePos(diff as u32);
|
|
||||||
line_start
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
4 => {
|
|
||||||
lines.extend((0..*num_diffs).map(|i| {
|
|
||||||
let pos = bytes_per_diff * i;
|
|
||||||
let bytes = [
|
|
||||||
raw_diffs[pos],
|
|
||||||
raw_diffs[pos + 1],
|
|
||||||
raw_diffs[pos + 2],
|
|
||||||
raw_diffs[pos + 3],
|
|
||||||
];
|
|
||||||
let diff = u32::from_le_bytes(bytes);
|
|
||||||
line_start = line_start + RelativeBytePos(diff);
|
|
||||||
line_start
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
let res = f(&lines);
|
|
||||||
*guard = SourceFileLines::Lines(lines);
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert from "diffs" form to "lines" form.
|
||||||
|
let num_lines = num_diffs + 1;
|
||||||
|
let mut lines = Vec::with_capacity(num_lines);
|
||||||
|
let mut line_start = RelativeBytePos(0);
|
||||||
|
lines.push(line_start);
|
||||||
|
|
||||||
|
assert_eq!(*num_diffs, raw_diffs.len() / bytes_per_diff);
|
||||||
|
match bytes_per_diff {
|
||||||
|
1 => {
|
||||||
|
lines.extend(raw_diffs.into_iter().map(|&diff| {
|
||||||
|
line_start = line_start + RelativeBytePos(diff as u32);
|
||||||
|
line_start
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
lines.extend((0..*num_diffs).map(|i| {
|
||||||
|
let pos = bytes_per_diff * i;
|
||||||
|
let bytes = [raw_diffs[pos], raw_diffs[pos + 1]];
|
||||||
|
let diff = u16::from_le_bytes(bytes);
|
||||||
|
line_start = line_start + RelativeBytePos(diff as u32);
|
||||||
|
line_start
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
4 => {
|
||||||
|
lines.extend((0..*num_diffs).map(|i| {
|
||||||
|
let pos = bytes_per_diff * i;
|
||||||
|
let bytes = [
|
||||||
|
raw_diffs[pos],
|
||||||
|
raw_diffs[pos + 1],
|
||||||
|
raw_diffs[pos + 2],
|
||||||
|
raw_diffs[pos + 3],
|
||||||
|
];
|
||||||
|
let diff = u32::from_le_bytes(bytes);
|
||||||
|
line_start = line_start + RelativeBytePos(diff);
|
||||||
|
line_start
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*guard = SourceFileLines::Lines(lines);
|
||||||
|
|
||||||
|
FreezeWriteGuard::freeze(guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lines(&self) -> &[RelativeBytePos] {
|
||||||
|
if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
|
||||||
|
return &lines[..];
|
||||||
|
}
|
||||||
|
|
||||||
|
cold_path(|| {
|
||||||
|
self.convert_diffs_to_lines_frozen();
|
||||||
|
if let Some(SourceFileLines::Lines(lines)) = self.lines.get() {
|
||||||
|
return &lines[..];
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `BytePos` of the beginning of the current line.
|
/// Returns the `BytePos` of the beginning of the current line.
|
||||||
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
|
pub fn line_begin_pos(&self, pos: BytePos) -> BytePos {
|
||||||
let pos = self.relative_position(pos);
|
let pos = self.relative_position(pos);
|
||||||
let line_index = self.lookup_line(pos).unwrap();
|
let line_index = self.lookup_line(pos).unwrap();
|
||||||
let line_start_pos = self.lines(|lines| lines[line_index]);
|
let line_start_pos = self.lines()[line_index];
|
||||||
self.absolute_position(line_start_pos)
|
self.absolute_position(line_start_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1612,35 +1627,37 @@ impl SourceFile {
|
||||||
where
|
where
|
||||||
F: FnOnce() -> Option<String>,
|
F: FnOnce() -> Option<String>,
|
||||||
{
|
{
|
||||||
if matches!(
|
if !self.external_src.is_frozen() {
|
||||||
*self.external_src.borrow(),
|
|
||||||
ExternalSource::Foreign { kind: ExternalSourceKind::AbsentOk, .. }
|
|
||||||
) {
|
|
||||||
let src = get_src();
|
let src = get_src();
|
||||||
let mut external_src = self.external_src.borrow_mut();
|
let src = src.and_then(|mut src| {
|
||||||
// Check that no-one else have provided the source while we were getting it
|
// The src_hash needs to be computed on the pre-normalized src.
|
||||||
if let ExternalSource::Foreign {
|
self.src_hash.matches(&src).then(|| {
|
||||||
kind: src_kind @ ExternalSourceKind::AbsentOk, ..
|
normalize_src(&mut src);
|
||||||
} = &mut *external_src
|
src
|
||||||
{
|
})
|
||||||
if let Some(mut src) = src {
|
});
|
||||||
// The src_hash needs to be computed on the pre-normalized src.
|
|
||||||
if self.src_hash.matches(&src) {
|
self.external_src.try_write().map(|mut external_src| {
|
||||||
normalize_src(&mut src);
|
if let ExternalSource::Foreign {
|
||||||
*src_kind = ExternalSourceKind::Present(Lrc::new(src));
|
kind: src_kind @ ExternalSourceKind::AbsentOk,
|
||||||
return true;
|
..
|
||||||
}
|
} = &mut *external_src
|
||||||
|
{
|
||||||
|
*src_kind = if let Some(src) = src {
|
||||||
|
ExternalSourceKind::Present(Lrc::new(src))
|
||||||
|
} else {
|
||||||
|
ExternalSourceKind::AbsentErr
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
*src_kind = ExternalSourceKind::AbsentErr;
|
panic!("unexpected state {:?}", *external_src)
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
// Freeze this so we don't try to load the source again.
|
||||||
} else {
|
FreezeWriteGuard::freeze(external_src)
|
||||||
self.src.is_some() || external_src.get_source().is_some()
|
});
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.src.is_some() || self.external_src.borrow().get_source().is_some()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.src.is_some() || self.external_src.read().get_source().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a line from the list of pre-computed line-beginnings.
|
/// Gets a line from the list of pre-computed line-beginnings.
|
||||||
|
@ -1658,7 +1675,7 @@ impl SourceFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
let begin = {
|
let begin = {
|
||||||
let line = self.lines(|lines| lines.get(line_number).copied())?;
|
let line = self.lines().get(line_number).copied()?;
|
||||||
line.to_usize()
|
line.to_usize()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1682,7 +1699,7 @@ impl SourceFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_lines(&self) -> usize {
|
pub fn count_lines(&self) -> usize {
|
||||||
self.lines(|lines| lines.len())
|
self.lines().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1705,7 +1722,7 @@ impl SourceFile {
|
||||||
/// number. If the source_file is empty or the position is located before the
|
/// number. If the source_file is empty or the position is located before the
|
||||||
/// first line, `None` is returned.
|
/// first line, `None` is returned.
|
||||||
pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
|
pub fn lookup_line(&self, pos: RelativeBytePos) -> Option<usize> {
|
||||||
self.lines(|lines| lines.partition_point(|x| x <= &pos).checked_sub(1))
|
self.lines().partition_point(|x| x <= &pos).checked_sub(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
|
pub fn line_bounds(&self, line_index: usize) -> Range<BytePos> {
|
||||||
|
@ -1713,15 +1730,13 @@ impl SourceFile {
|
||||||
return self.start_pos..self.start_pos;
|
return self.start_pos..self.start_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lines(|lines| {
|
let lines = self.lines();
|
||||||
assert!(line_index < lines.len());
|
assert!(line_index < lines.len());
|
||||||
if line_index == (lines.len() - 1) {
|
if line_index == (lines.len() - 1) {
|
||||||
self.absolute_position(lines[line_index])..self.end_position()
|
self.absolute_position(lines[line_index])..self.end_position()
|
||||||
} else {
|
} else {
|
||||||
self.absolute_position(lines[line_index])
|
self.absolute_position(lines[line_index])..self.absolute_position(lines[line_index + 1])
|
||||||
..self.absolute_position(lines[line_index + 1])
|
}
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether or not the file contains the given `SourceMap` byte
|
/// Returns whether or not the file contains the given `SourceMap` byte
|
||||||
|
@ -1807,7 +1822,7 @@ impl SourceFile {
|
||||||
match self.lookup_line(pos) {
|
match self.lookup_line(pos) {
|
||||||
Some(a) => {
|
Some(a) => {
|
||||||
let line = a + 1; // Line numbers start at 1
|
let line = a + 1; // Line numbers start at 1
|
||||||
let linebpos = self.lines(|lines| lines[a]);
|
let linebpos = self.lines()[a];
|
||||||
let linechpos = self.bytepos_to_file_charpos(linebpos);
|
let linechpos = self.bytepos_to_file_charpos(linebpos);
|
||||||
let col = chpos - linechpos;
|
let col = chpos - linechpos;
|
||||||
debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
|
debug!("byte pos {:?} is on the line at byte pos {:?}", pos, linebpos);
|
||||||
|
@ -1827,7 +1842,7 @@ impl SourceFile {
|
||||||
let (line, col_or_chpos) = self.lookup_file_pos(pos);
|
let (line, col_or_chpos) = self.lookup_file_pos(pos);
|
||||||
if line > 0 {
|
if line > 0 {
|
||||||
let col = col_or_chpos;
|
let col = col_or_chpos;
|
||||||
let linebpos = self.lines(|lines| lines[line - 1]);
|
let linebpos = self.lines()[line - 1];
|
||||||
let col_display = {
|
let col_display = {
|
||||||
let start_width_idx = self
|
let start_width_idx = self
|
||||||
.non_narrow_chars
|
.non_narrow_chars
|
||||||
|
|
|
@ -328,7 +328,7 @@ impl SourceMap {
|
||||||
name_hash: Hash128,
|
name_hash: Hash128,
|
||||||
source_len: u32,
|
source_len: u32,
|
||||||
cnum: CrateNum,
|
cnum: CrateNum,
|
||||||
file_local_lines: Lock<SourceFileLines>,
|
file_local_lines: FreezeLock<SourceFileLines>,
|
||||||
multibyte_chars: Vec<MultiByteChar>,
|
multibyte_chars: Vec<MultiByteChar>,
|
||||||
non_narrow_chars: Vec<NonNarrowChar>,
|
non_narrow_chars: Vec<NonNarrowChar>,
|
||||||
normalized_pos: Vec<NormalizedPos>,
|
normalized_pos: Vec<NormalizedPos>,
|
||||||
|
@ -340,7 +340,7 @@ impl SourceMap {
|
||||||
name: filename,
|
name: filename,
|
||||||
src: None,
|
src: None,
|
||||||
src_hash,
|
src_hash,
|
||||||
external_src: Lock::new(ExternalSource::Foreign {
|
external_src: FreezeLock::new(ExternalSource::Foreign {
|
||||||
kind: ExternalSourceKind::AbsentOk,
|
kind: ExternalSourceKind::AbsentOk,
|
||||||
metadata_index,
|
metadata_index,
|
||||||
}),
|
}),
|
||||||
|
@ -564,7 +564,7 @@ impl SourceMap {
|
||||||
end: (local_end.sf.name.clone(), local_end.sf.start_pos),
|
end: (local_end.sf.name.clone(), local_end.sf.start_pos),
|
||||||
})))
|
})))
|
||||||
} else {
|
} else {
|
||||||
self.ensure_source_file_source_present(local_begin.sf.clone());
|
self.ensure_source_file_source_present(&local_begin.sf);
|
||||||
|
|
||||||
let start_index = local_begin.pos.to_usize();
|
let start_index = local_begin.pos.to_usize();
|
||||||
let end_index = local_end.pos.to_usize();
|
let end_index = local_end.pos.to_usize();
|
||||||
|
@ -581,7 +581,7 @@ impl SourceMap {
|
||||||
|
|
||||||
if let Some(ref src) = local_begin.sf.src {
|
if let Some(ref src) = local_begin.sf.src {
|
||||||
extract_source(src, start_index, end_index)
|
extract_source(src, start_index, end_index)
|
||||||
} else if let Some(src) = local_begin.sf.external_src.borrow().get_source() {
|
} else if let Some(src) = local_begin.sf.external_src.read().get_source() {
|
||||||
extract_source(src, start_index, end_index)
|
extract_source(src, start_index, end_index)
|
||||||
} else {
|
} else {
|
||||||
Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
|
Err(SpanSnippetError::SourceNotAvailable { filename: local_begin.sf.name.clone() })
|
||||||
|
@ -873,7 +873,7 @@ impl SourceMap {
|
||||||
let sp = sp.data();
|
let sp = sp.data();
|
||||||
let local_begin = self.lookup_byte_offset(sp.lo);
|
let local_begin = self.lookup_byte_offset(sp.lo);
|
||||||
let start_index = local_begin.pos.to_usize();
|
let start_index = local_begin.pos.to_usize();
|
||||||
let src = local_begin.sf.external_src.borrow();
|
let src = local_begin.sf.external_src.read();
|
||||||
|
|
||||||
let snippet = if let Some(ref src) = local_begin.sf.src {
|
let snippet = if let Some(ref src) = local_begin.sf.src {
|
||||||
Some(&src[start_index..])
|
Some(&src[start_index..])
|
||||||
|
@ -983,7 +983,7 @@ impl SourceMap {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let src = local_begin.sf.external_src.borrow();
|
let src = local_begin.sf.external_src.read();
|
||||||
|
|
||||||
let snippet = if let Some(src) = &local_begin.sf.src {
|
let snippet = if let Some(src) = &local_begin.sf.src {
|
||||||
src
|
src
|
||||||
|
@ -1030,7 +1030,7 @@ impl SourceMap {
|
||||||
self.files().iter().fold(0, |a, f| a + f.count_lines())
|
self.files().iter().fold(0, |a, f| a + f.count_lines())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
|
pub fn ensure_source_file_source_present(&self, source_file: &SourceFile) -> bool {
|
||||||
source_file.add_external_src(|| {
|
source_file.add_external_src(|| {
|
||||||
let FileName::Real(ref name) = source_file.name else {
|
let FileName::Real(ref name) = source_file.name else {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::{FreezeLock, Lrc};
|
||||||
|
|
||||||
fn init_source_map() -> SourceMap {
|
fn init_source_map() -> SourceMap {
|
||||||
let sm = SourceMap::new(FilePathMapping::empty());
|
let sm = SourceMap::new(FilePathMapping::empty());
|
||||||
|
@ -246,7 +246,7 @@ fn t10() {
|
||||||
name_hash,
|
name_hash,
|
||||||
source_len.to_u32(),
|
source_len.to_u32(),
|
||||||
CrateNum::new(0),
|
CrateNum::new(0),
|
||||||
lines,
|
FreezeLock::new(lines.read().clone()),
|
||||||
multibyte_chars,
|
multibyte_chars,
|
||||||
non_narrow_chars,
|
non_narrow_chars,
|
||||||
normalized_pos,
|
normalized_pos,
|
||||||
|
|
|
@ -7,9 +7,7 @@ fn test_lookup_line() {
|
||||||
SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256)
|
SourceFile::new(FileName::Anon(Hash64::ZERO), source, SourceFileHashAlgorithm::Sha256)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
sf.start_pos = BytePos(3);
|
sf.start_pos = BytePos(3);
|
||||||
sf.lines(|lines| {
|
assert_eq!(sf.lines(), &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)]);
|
||||||
assert_eq!(lines, &[RelativeBytePos(0), RelativeBytePos(14), RelativeBytePos(25)])
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0));
|
assert_eq!(sf.lookup_line(RelativeBytePos(0)), Some(0));
|
||||||
assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0));
|
assert_eq!(sf.lookup_line(RelativeBytePos(1)), Some(0));
|
||||||
|
|
|
@ -507,20 +507,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
|
||||||
&& Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
|
&& Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
|
||||||
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
||||||
{
|
{
|
||||||
return unsafe_line.sf.lines(|lines| {
|
return if comment_start_line.line >= unsafe_line.line {
|
||||||
if comment_start_line.line >= unsafe_line.line {
|
HasSafetyComment::No
|
||||||
HasSafetyComment::No
|
} else {
|
||||||
} else {
|
match text_has_safety_comment(
|
||||||
match text_has_safety_comment(
|
src,
|
||||||
src,
|
&unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
|
||||||
&lines[comment_start_line.line + 1..=unsafe_line.line],
|
unsafe_line.sf.start_pos,
|
||||||
unsafe_line.sf.start_pos,
|
) {
|
||||||
) {
|
Some(b) => HasSafetyComment::Yes(b),
|
||||||
Some(b) => HasSafetyComment::Yes(b),
|
None => HasSafetyComment::No,
|
||||||
None => HasSafetyComment::No,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HasSafetyComment::Maybe
|
HasSafetyComment::Maybe
|
||||||
|
@ -551,20 +549,18 @@ fn stmt_has_safety_comment(cx: &LateContext<'_>, span: Span, hir_id: HirId) -> H
|
||||||
&& Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
|
&& Lrc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)
|
||||||
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
||||||
{
|
{
|
||||||
return unsafe_line.sf.lines(|lines| {
|
return if comment_start_line.line >= unsafe_line.line {
|
||||||
if comment_start_line.line >= unsafe_line.line {
|
HasSafetyComment::No
|
||||||
HasSafetyComment::No
|
} else {
|
||||||
} else {
|
match text_has_safety_comment(
|
||||||
match text_has_safety_comment(
|
src,
|
||||||
src,
|
&unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line],
|
||||||
&lines[comment_start_line.line + 1..=unsafe_line.line],
|
unsafe_line.sf.start_pos,
|
||||||
unsafe_line.sf.start_pos,
|
) {
|
||||||
) {
|
Some(b) => HasSafetyComment::Yes(b),
|
||||||
Some(b) => HasSafetyComment::Yes(b),
|
None => HasSafetyComment::No,
|
||||||
None => HasSafetyComment::No,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HasSafetyComment::Maybe
|
HasSafetyComment::Maybe
|
||||||
|
@ -614,20 +610,18 @@ fn span_from_macro_expansion_has_safety_comment(cx: &LateContext<'_>, span: Span
|
||||||
&& Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf)
|
&& Lrc::ptr_eq(&unsafe_line.sf, ¯o_line.sf)
|
||||||
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
&& let Some(src) = unsafe_line.sf.src.as_deref()
|
||||||
{
|
{
|
||||||
unsafe_line.sf.lines(|lines| {
|
if macro_line.line < unsafe_line.line {
|
||||||
if macro_line.line < unsafe_line.line {
|
match text_has_safety_comment(
|
||||||
match text_has_safety_comment(
|
src,
|
||||||
src,
|
&unsafe_line.sf.lines()[macro_line.line + 1..=unsafe_line.line],
|
||||||
&lines[macro_line.line + 1..=unsafe_line.line],
|
unsafe_line.sf.start_pos,
|
||||||
unsafe_line.sf.start_pos,
|
) {
|
||||||
) {
|
Some(b) => HasSafetyComment::Yes(b),
|
||||||
Some(b) => HasSafetyComment::Yes(b),
|
None => HasSafetyComment::No,
|
||||||
None => HasSafetyComment::No,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
HasSafetyComment::No
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
|
HasSafetyComment::No
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Problem getting source text. Pretend a comment was found.
|
// Problem getting source text. Pretend a comment was found.
|
||||||
HasSafetyComment::Maybe
|
HasSafetyComment::Maybe
|
||||||
|
@ -671,13 +665,11 @@ fn span_in_body_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
|
||||||
// Get the text from the start of function body to the unsafe block.
|
// Get the text from the start of function body to the unsafe block.
|
||||||
// fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
|
// fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
|
||||||
// ^-------------^
|
// ^-------------^
|
||||||
unsafe_line.sf.lines(|lines| {
|
body_line.line < unsafe_line.line && text_has_safety_comment(
|
||||||
body_line.line < unsafe_line.line && text_has_safety_comment(
|
src,
|
||||||
src,
|
&unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
|
||||||
&lines[body_line.line + 1..=unsafe_line.line],
|
unsafe_line.sf.start_pos,
|
||||||
unsafe_line.sf.start_pos,
|
).is_some()
|
||||||
).is_some()
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
// Problem getting source text. Pretend a comment was found.
|
// Problem getting source text. Pretend a comment was found.
|
||||||
true
|
true
|
||||||
|
|
|
@ -118,7 +118,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
|
||||||
fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
|
fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
|
||||||
let span = original_sp(span, DUMMY_SP);
|
let span = original_sp(span, DUMMY_SP);
|
||||||
let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
|
let SourceFileAndLine { sf, line } = cx.sess().source_map().lookup_line(span.lo()).unwrap();
|
||||||
let line_start = sf.lines(|lines| lines[line]);
|
let line_start = sf.lines()[line];
|
||||||
let line_start = sf.absolute_position(line_start);
|
let line_start = sf.absolute_position(line_start);
|
||||||
span.with_lo(line_start)
|
span.with_lo(line_start)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue