"humantime 2.0.1",
"ignore",
"im-rc",
+ "indexmap",
"itertools",
"jobserver",
"lazy_static",
"serde_ignored",
"serde_json",
"shell-escape",
+ "snapbox",
"strip-ansi-escapes",
"tar",
"tempfile",
"winapi",
]
+[[package]]
+name = "concolor"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
+dependencies = [
+ "atty",
+ "bitflags",
+ "concolor-query",
+]
+
+[[package]]
+name = "concolor-query"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
+
+[[package]]
+name = "content_inspector"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "core"
version = "0.0.0"
"rustc-std-workspace-core",
]
+[[package]]
+name = "dunce"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541"
+
[[package]]
name = "either"
version = "1.6.0"
"version_check",
]
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
[[package]]
name = "ntapi"
version = "0.3.6"
[[package]]
name = "openssl"
-version = "0.10.35"
+version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "549430950c79ae24e6d02e0b7404534ecf311d94cc9f861e9e4020187d13d885"
+checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
"bitflags",
"cfg-if 1.0.0",
[[package]]
name = "openssl-sys"
-version = "0.9.65"
+version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d"
+checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
"autocfg",
"cc",
name = "proc_macro"
version = "0.0.0"
dependencies = [
+ "core",
"std",
]
"rustc_infer",
"rustc_middle",
"rustc_parse_format",
- "rustc_serialize",
"rustc_session",
"rustc_span",
"rustc_target",
"libc",
]
+[[package]]
+name = "similar"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
+
[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"
+[[package]]
+name = "snapbox"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1f212b806d6f56d19838e36a0aaa7e79a0bc9ca177e873fb87651ad92f983e2"
+dependencies = [
+ "concolor",
+ "content_inspector",
+ "dunce",
+ "filetime",
+ "normalize-line-endings",
+ "similar",
+ "snapbox-macros",
+ "tempfile",
+ "walkdir",
+ "yansi",
+]
+
+[[package]]
+name = "snapbox-macros"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c01dea7e04cbb27ef4c86e9922184608185f7cd95c1763bc30d727cda4a5e930"
+
[[package]]
name = "socket2"
version = "0.4.1"
[[package]]
name = "walkdir"
-version = "2.3.1"
+version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"linked-hash-map",
]
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+
[[package]]
name = "yansi-term"
version = "0.1.2"
use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use crate::tokenstream::{DelimSpan, Spacing, TokenTree, TreeAndSpacing};
use crate::tokenstream::{LazyTokenStream, TokenStream};
+use crate::util::comments;
use rustc_index::bit_set::GrowableBitSet;
use rustc_span::source_map::BytePos;
}
}
+ pub fn may_have_doc_links(&self) -> bool {
+ self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
+ }
+
pub fn get_normal_item(&self) -> &AttrItem {
match self.kind {
AttrKind::Normal(ref item, _) => item,
pub pos: BytePos,
}
+/// A fast conservative estimate on whether the string can contain documentation links.
+/// A pair of square brackets `[]` must exist in the string, but we only search for the
+/// opening bracket because brackets always go in pairs in practice.
+#[inline]
+pub fn may_have_doc_links(s: &str) -> bool {
+ s.contains('[')
+}
+
/// Makes a doc string more presentable to users.
/// Used by rustdoc and perhaps other tools, but not by rustc.
pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol {
sup: self.static_region,
sub: next_static_idx.into(),
locations: Locations::All(DUMMY_SP),
+ span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
})
use rustc_index::vec::IndexVec;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
+use rustc_span::Span;
use std::fmt;
use std::ops::Index;
/// Where did this constraint arise?
pub locations: Locations,
+ /// The `Span` associated with the creation of this constraint.
+ /// This should be used in preference to obtaining the span from
+ /// `locations`, since the `locations` may give a poor span
+ /// in some cases (e.g. converting a constraint from a promoted).
+ pub span: Span,
+
/// What caused this constraint?
pub category: ConstraintCategory,
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
for constraint in &constraints {
- let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
+ let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
+ constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
}
Locations::Single(loc) => ("Single", format!("{:?}", loc)),
};
- with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
+ with_msg(&format!(
+ "{:?}: {:?} due to {:?} at {}({}) ({:?}",
+ sup, sub, category, name, arg, span
+ ))?;
}
Ok(())
crate fn retrieve_closure_constraint_info(
&self,
- body: &Body<'tcx>,
+ _body: &Body<'tcx>,
constraint: &OutlivesConstraint<'tcx>,
) -> BlameConstraint<'tcx> {
let loc = match constraint.locations {
.unwrap_or(BlameConstraint {
category: constraint.category,
from_closure: false,
- cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
+ cause: ObligationCause::dummy_with_span(constraint.span),
variance_info: constraint.variance_info,
})
}
sup: r,
sub: constraint.min_choice,
locations: Locations::All(p_c.definition_span),
+ span: p_c.definition_span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
};
category: constraint.category,
from_closure: false,
cause: ObligationCause::new(
- constraint.locations.span(body),
+ constraint.span,
CRATE_HIR_ID,
cause_code.clone(),
),
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
use crate::{
constraints::OutlivesConstraint,
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
+ span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
implicit_region_bound: Option<ty::Region<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
+ span: Span,
category: ConstraintCategory,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
) -> Self {
implicit_region_bound,
param_env,
locations,
+ span,
category,
constraints,
}
self.constraints.outlives_constraints.push(OutlivesConstraint {
locations: self.locations,
category: self.category,
+ span: self.span,
sub,
sup,
variance_info: ty::VarianceDiagInfo::default(),
self.implicit_region_bound,
self.param_env,
Locations::All(DUMMY_SP),
+ DUMMY_SP,
ConstraintCategory::Internal,
&mut self.constraints,
)
Some(self.implicit_region_bound),
self.param_env,
Locations::All(DUMMY_SP),
+ DUMMY_SP,
ConstraintCategory::Internal,
&mut self.borrowck_context.constraints,
)
Some(self.implicit_region_bound),
self.param_env,
locations,
+ locations.span(self.body),
category,
&mut self.borrowck_context.constraints,
)
sup: ref_region.to_region_vid(),
sub: borrow_region.to_region_vid(),
locations: location.to_locations(),
+ span: location.to_locations().span(body),
category,
variance_info: ty::VarianceDiagInfo::default(),
});
sup,
sub,
locations: self.locations,
+ span: self.locations.span(self.type_checker.body),
category: self.category,
variance_info: info,
},
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
InlineAsmRegClass::X86(
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => cx.type_i16(),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
_ => unreachable!(),
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => None,
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::X86(
- X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
) => unreachable!("clobber-only"),
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
_ => unreachable!(),
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
- InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
+ ) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
- InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::kreg0,
+ ) => {
unreachable!("clobber-only")
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
use std::collections::hash_map::Entry::*;
use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::Node;
-use rustc_index::vec::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
let mut instances: DefIdMap<FxHashMap<_, _>> = Default::default();
- let cnum_stable_ids: IndexVec<CrateNum, Fingerprint> = {
- let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, cnums.len() + 1);
-
- for &cnum in cnums.iter() {
- cnum_stable_ids[cnum] =
- tcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).0;
- }
-
- cnum_stable_ids
- };
-
let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn();
for &cnum in cnums.iter() {
// If there are multiple monomorphizations available,
// we select one deterministically.
let other_cnum = *e.get();
- if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] {
+ if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) {
e.insert(cnum);
}
}
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
bug!("intern_const_alloc_recursive should not error in this case")
}
- ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
+ ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
}
/// Convert an evaluated constant to a type level constant
return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
return_to_block: StackPopCleanup,
) -> InterpResult<'tcx> {
- debug!("body: {:#?}", body);
+ trace!("body: {:#?}", body);
// first push a stack frame so we have access to the local substs
let pre_frame = Frame {
body,
return Ok(());
}
- debug!("locals: {:#?}", frame.locals);
+ trace!("locals: {:#?}", frame.locals);
// Cleanup: deallocate all locals that are backed by an allocation.
for local in &frame.locals {
/// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to.
type PointerTag: Provenance + Eq + Hash + 'static;
+ /// When getting the AllocId of a pointer, some extra data is also obtained from the tag
+ /// that is passed to memory access hooks so they can do things with it.
+ type TagExtra: Copy + 'static;
+
/// Machines can define extra (non-instance) things that represent values of function pointers.
/// For example, Miri uses this to return a function pointer from `dlsym`
/// that can later be called to execute the right thing.
/// Whether, when checking alignment, we should `force_int` and thus support
/// custom alignment logic based on whatever the integer address happens to be.
+ ///
+ /// Requires PointerTag::OFFSET_IS_ADDR to be true.
fn force_int_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
/// Whether to enforce the validity invariant
addr: u64,
) -> Pointer<Option<Self::PointerTag>>;
- /// Convert a pointer with provenance into an allocation-offset pair.
+ /// Convert a pointer with provenance into an allocation-offset pair
+ /// and extra provenance info.
+ ///
+ /// The returned `AllocId` must be the same as `ptr.provenance.get_alloc_id()`.
fn ptr_get_alloc(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer<Self::PointerTag>,
- ) -> (AllocId, Size);
+ ) -> (AllocId, Size, Self::TagExtra);
/// Called to initialize the "extra" state of an allocation and make the pointers
/// it contains (in relocations) tagged. The way we construct allocations is
_tcx: TyCtxt<'tcx>,
_machine: &Self,
_alloc_extra: &Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
- _tag: Self::PointerTag,
+ _tag: (AllocId, Self::TagExtra),
_range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
// (CTFE and ConstProp) use the same instance. Here, we share that code.
pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
type PointerTag = AllocId;
+ type TagExtra = ();
+
type ExtraFnVal = !;
type MemoryMap =
}
#[inline(always)]
- fn ptr_get_alloc(_ecx: &InterpCx<$mir, $tcx, Self>, ptr: Pointer<AllocId>) -> (AllocId, Size) {
+ fn ptr_get_alloc(
+ _ecx: &InterpCx<$mir, $tcx, Self>,
+ ptr: Pointer<AllocId>,
+ ) -> (AllocId, Size, Self::TagExtra) {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = ptr.into_parts();
- (alloc_id, offset)
+ (alloc_id, offset, ())
}
}
&self,
ptr: Pointer<AllocId>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
- // We know `offset` is relative to the allocation, so we can use `into_parts`.
- let (alloc_id, offset) = ptr.into_parts();
+ let alloc_id = ptr.provenance;
// We need to handle `extern static`.
match self.tcx.get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
_ => {}
}
// And we need to get the tag.
- Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset)))
+ Ok(M::tag_alloc_base_pointer(self, ptr))
}
pub fn create_fn_alloc_ptr(
new_align: Align,
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
- let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub_format!(
"reallocating {:?} which does not point to the beginning of an object",
};
// This will also call the access hooks.
self.mem_copy(
- ptr.into(),
+ ptr,
Align::ONE,
new_ptr.into(),
Align::ONE,
old_size.min(new_size),
/*nonoverlapping*/ true,
)?;
- self.deallocate_ptr(ptr.into(), old_size_and_align, kind)?;
+ self.deallocate_ptr(ptr, old_size_and_align, kind)?;
Ok(new_ptr)
}
old_size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx> {
- let (alloc_id, offset, ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
trace!("deallocating: {}", alloc_id);
if offset.bytes() != 0 {
*self.tcx,
&mut self.machine,
&mut alloc.extra,
- ptr.provenance,
+ (alloc_id, tag),
alloc_range(Size::ZERO, size),
)?;
ptr: Pointer<Option<M::PointerTag>>,
size: Size,
align: Align,
- ) -> InterpResult<'tcx, Option<(AllocId, Size, Pointer<M::PointerTag>)>> {
+ ) -> InterpResult<'tcx, Option<(AllocId, Size, M::TagExtra)>> {
let align = M::enforce_alignment(&self).then_some(align);
self.check_and_deref_ptr(
ptr,
size,
align,
CheckInAllocMsg::MemoryAccessTest,
- |alloc_id, offset, ptr| {
+ |alloc_id, offset, tag| {
let (size, align) =
self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?;
- Ok((size, align, (alloc_id, offset, ptr)))
+ Ok((size, align, (alloc_id, offset, tag)))
},
)
}
size: Size,
align: Option<Align>,
msg: CheckInAllocMsg,
- alloc_size: impl FnOnce(
- AllocId,
- Size,
- Pointer<M::PointerTag>,
- ) -> InterpResult<'tcx, (Size, Align, T)>,
+ alloc_size: impl FnOnce(AllocId, Size, M::TagExtra) -> InterpResult<'tcx, (Size, Align, T)>,
) -> InterpResult<'tcx, Option<T>> {
fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
if offset % align.bytes() == 0 {
}
None
}
- Ok((alloc_id, offset, ptr)) => {
- let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, ptr)?;
+ Ok((alloc_id, offset, tag)) => {
+ let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, tag)?;
// Test bounds. This also ensures non-null.
// It is sufficient to check this for the end pointer. Also check for overflow!
if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
// we want the error to be about the bounds.
if let Some(align) = align {
if M::force_int_for_alignment_check(self) {
- let addr = Scalar::from_pointer(ptr, &self.tcx)
- .to_machine_usize(&self.tcx)
- .expect("ptr-to-int cast for align check should never fail");
- check_offset_align(addr, align)?;
+ // `force_int_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true.
+ check_offset_align(ptr.addr().bytes(), align)?;
} else {
// Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() {
size,
align,
CheckInAllocMsg::MemoryAccessTest,
- |alloc_id, offset, ptr| {
+ |alloc_id, offset, tag| {
let alloc = self.get_alloc_raw(alloc_id)?;
- Ok((alloc.size(), alloc.align, (alloc_id, offset, ptr, alloc)))
+ Ok((alloc.size(), alloc.align, (alloc_id, offset, tag, alloc)))
},
)?;
- if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc {
+ if let Some((alloc_id, offset, tag, alloc)) = ptr_and_alloc {
let range = alloc_range(offset, size);
- M::memory_read(*self.tcx, &self.machine, &alloc.extra, ptr.provenance, range)?;
+ M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, tag), range)?;
Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
} else {
// Even in this branch we have to be sure that we actually access the allocation, in
align: Align,
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
let parts = self.get_ptr_access(ptr, size, align)?;
- if let Some((alloc_id, offset, ptr)) = parts {
+ if let Some((alloc_id, offset, tag)) = parts {
let tcx = *self.tcx;
// FIXME: can we somehow avoid looking up the allocation twice here?
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
let range = alloc_range(offset, size);
- M::memory_written(tcx, machine, &mut alloc.extra, ptr.provenance, range)?;
+ M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, tag), range)?;
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
} else {
Ok(None)
ptr: Pointer<Option<M::PointerTag>>,
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
trace!("get_fn({:?})", ptr);
- let (alloc_id, offset, _ptr) = self.ptr_get_alloc_id(ptr)?;
+ let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
}
range: AllocRange,
val: ScalarMaybeUninit<Tag>,
) -> InterpResult<'tcx> {
+ let range = self.range.subrange(range);
+ debug!(
+ "write_scalar in {} at {:#x}, size {}: {:?}",
+ self.alloc_id,
+ range.start.bytes(),
+ range.size.bytes(),
+ val
+ );
Ok(self
.alloc
- .write_scalar(&self.tcx, self.range.subrange(range), val)
+ .write_scalar(&self.tcx, range, val)
.map_err(|e| e.to_interp_error(self.alloc_id))?)
}
}
/// Mark the entire referenced range as uninitalized
- pub fn write_uninit(&mut self) {
- self.alloc.mark_init(self.range, false);
+ pub fn write_uninit(&mut self) -> InterpResult<'tcx> {
+ Ok(self
+ .alloc
+ .write_uninit(&self.tcx, self.range)
+ .map_err(|e| e.to_interp_error(self.alloc_id))?)
}
}
impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
- Ok(self
+ let range = self.range.subrange(range);
+ let res = self
.alloc
- .read_scalar(&self.tcx, self.range.subrange(range))
- .map_err(|e| e.to_interp_error(self.alloc_id))?)
+ .read_scalar(&self.tcx, range)
+ .map_err(|e| e.to_interp_error(self.alloc_id))?;
+ debug!(
+ "read_scalar in {} at {:#x}, size {}: {:?}",
+ self.alloc_id,
+ range.start.bytes(),
+ range.size.bytes(),
+ res
+ );
+ Ok(res)
}
pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
// and once below to get the underlying `&[mut] Allocation`.
// Source alloc preparations and access hooks.
- let Some((src_alloc_id, src_offset, src)) = src_parts else {
+ let Some((src_alloc_id, src_offset, src_tag)) = src_parts else {
// Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
return Ok(());
};
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
let src_range = alloc_range(src_offset, size);
- M::memory_read(*tcx, &self.machine, &src_alloc.extra, src.provenance, src_range)?;
+ M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_tag), src_range)?;
// We need the `dest` ptr for the next operation, so we get it now.
// We already did the source checks and called the hooks so we are good to return early.
- let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
+ let Some((dest_alloc_id, dest_offset, dest_tag)) = dest_parts else {
// Zero-sized *destination*.
return Ok(());
};
// Destination alloc preparations and access hooks.
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
let dest_range = alloc_range(dest_offset, size * num_copies);
- M::memory_written(*tcx, extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
+ M::memory_written(
+ *tcx,
+ extra,
+ &mut dest_alloc.extra,
+ (dest_alloc_id, dest_tag),
+ dest_range,
+ )?;
let dest_bytes = dest_alloc
.get_bytes_mut_ptr(&tcx, dest_range)
.map_err(|e| e.to_interp_error(dest_alloc_id))?
// This also avoids writing to the target bytes so that the backing allocation is never
// touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
// operating system this can avoid physically allocating the page.
- dest_alloc.mark_init(dest_range, false); // `Size` multiplication
- dest_alloc.mark_relocation_range(relocations);
+ dest_alloc
+ .write_uninit(&tcx, dest_range)
+ .map_err(|e| e.to_interp_error(dest_alloc_id))?;
+ // We can forget about the relocations, this is all not initialized anyway.
return Ok(());
}
pub fn ptr_try_get_alloc_id(
&self,
ptr: Pointer<Option<M::PointerTag>>,
- ) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> {
+ ) -> Result<(AllocId, Size, M::TagExtra), u64> {
match ptr.into_pointer_or_addr() {
Ok(ptr) => {
- let (alloc_id, offset) = M::ptr_get_alloc(self, ptr);
- Ok((alloc_id, offset, ptr))
+ let (alloc_id, offset, extra) = M::ptr_get_alloc(self, ptr);
+ Ok((alloc_id, offset, extra))
}
Err(addr) => Err(addr.bytes()),
}
pub fn ptr_get_alloc_id(
&self,
ptr: Pointer<Option<M::PointerTag>>,
- ) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> {
+ ) -> InterpResult<'tcx, (AllocId, Size, M::TagExtra)> {
self.ptr_try_get_alloc_id(ptr).map_err(|offset| {
err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
})
// Zero-sized access
return Ok(());
};
- alloc.write_uninit();
+ alloc.write_uninit()?;
Ok(())
}
if let Some(ref mut ref_tracking) = self.ref_tracking {
// Proceed recursively even for ZST, no reason to skip them!
// `!` is a ZST and we want to validate it.
- if let Ok((alloc_id, _offset, _ptr)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
+ if let Ok((alloc_id, _offset, _tag)) = self.ecx.ptr_try_get_alloc_id(place.ptr) {
// Special handling for pointers to statics (irrespective of their type).
let alloc_kind = self.ecx.tcx.get_global_alloc(alloc_id);
if let Some(GlobalAlloc::Static(did)) = alloc_kind {
fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
}
-// Implement HashStable by just calling `Hash::hash()`. This works fine for
-// self-contained values that don't depend on the hashing context `CTX`.
-#[macro_export]
+/// Implement HashStable by just calling `Hash::hash()`.
+///
+/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
+/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
+/// for examples). Therefore this macro is not exported and should only be used in the limited cases
+/// here in this module.
+///
+/// Use `#[derive(HashStable_Generic)]` instead.
macro_rules! impl_stable_hash_via_hash {
($t:ty) => {
impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
}
impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.get().hash_stable(ctx, hasher)
}
}
impl<CTX> HashStable<CTX> for ::std::num::NonZeroUsize {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.get().hash_stable(ctx, hasher)
}
}
impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
(*self as i8).hash_stable(ctx, hasher);
}
}
impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
+ #[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
let (ref _0,) = *self;
_0.hash_stable(ctx, hasher);
/// Returns `true` if any of the primary spans are displayable.
pub fn has_primary_spans(&self) -> bool {
- self.primary_spans.iter().any(|sp| !sp.is_dummy())
+ !self.is_dummy()
}
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
pub fn is_dummy(&self) -> bool {
- let mut is_dummy = true;
- for span in &self.primary_spans {
- if !span.is_dummy() {
- is_dummy = false;
- }
- }
- is_dummy
+ self.primary_spans.iter().all(|sp| sp.is_dummy())
}
/// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't
use crate::snippet::Style;
use crate::{
CodeSuggestion, DiagnosticMessage, Level, MultiSpan, Substitution, SubstitutionPart,
- SuggestionStyle, ToolMetadata,
+ SuggestionStyle,
};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_error_messages::FluentValue;
use rustc_lint_defs::{Applicability, LintExpectationId};
-use rustc_serialize::json::Json;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
msg: msg.into(),
style,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::CompletelyHidden,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
- tool_metadata: Default::default(),
});
self
}
msg: msg.into(),
style: SuggestionStyle::ShowCode,
applicability,
- tool_metadata: Default::default(),
});
self
}
self
}
- /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes
- /// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
- pub fn tool_only_suggestion_with_metadata(
- &mut self,
- msg: impl Into<DiagnosticMessage>,
- applicability: Applicability,
- tool_metadata: Json,
- ) {
- self.push_suggestion(CodeSuggestion {
- substitutions: vec![],
- msg: msg.into(),
- style: SuggestionStyle::CompletelyHidden,
- applicability,
- tool_metadata: ToolMetadata::new(tool_metadata),
- })
- }
-
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::DiagnosticId;
-use crate::ToolMetadata;
use crate::{
CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
};
use std::vec;
use rustc_serialize::json::{as_json, as_pretty_json};
-use rustc_serialize::{Encodable, Encoder};
#[cfg(test)]
mod tests;
// The following data types are provided just for serialisation.
-// NOTE: this has a manual implementation of Encodable which needs to be updated in
-// parallel.
+#[derive(Encodable)]
struct Diagnostic {
/// The primary error message.
message: String,
children: Vec<Diagnostic>,
/// The message as rustc would render it.
rendered: Option<String>,
- /// Extra tool metadata
- tool_metadata: ToolMetadata,
-}
-
-macro_rules! encode_fields {
- (
- $enc:expr, // encoder
- $idx:expr, // starting field index
- $struct:expr, // struct we're serializing
- $struct_name:ident, // struct name
- [ $($name:ident),+$(,)? ], // fields to encode
- [ $($ignore:ident),+$(,)? ] // fields we're skipping
- ) => {
- {
- // Pattern match to make sure all fields are accounted for
- let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct;
- let mut idx = $idx;
- $(
- $enc.emit_struct_field(
- stringify!($name),
- idx == 0,
- |enc| $name.encode(enc),
- )?;
- idx += 1;
- )+
- idx
- }
- };
-}
-
-// Special-case encoder to skip tool_metadata if not set
-impl<E: Encoder> Encodable<E> for Diagnostic {
- fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_struct(false, |s| {
- let mut idx = 0;
-
- idx = encode_fields!(
- s,
- idx,
- self,
- Self,
- [message, code, level, spans, children, rendered],
- [tool_metadata]
- );
- if self.tool_metadata.is_set() {
- idx = encode_fields!(
- s,
- idx,
- self,
- Self,
- [tool_metadata],
- [message, code, level, spans, children, rendered]
- );
- }
-
- let _ = idx;
- Ok(())
- })
- }
}
#[derive(Encodable)]
spans: DiagnosticSpan::from_suggestion(sugg, &args, je),
children: vec![],
rendered: None,
- tool_metadata: sugg.tool_metadata.clone(),
}
});
.chain(sugg)
.collect(),
rendered: Some(output),
- tool_metadata: ToolMetadata::default(),
}
}
.unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, args, je)),
children: vec![],
rendered: None,
- tool_metadata: ToolMetadata::default(),
}
}
}
LazyFallbackBundle, MultiSpan, SpanLabel, DEFAULT_LOCALE_RESOURCES,
};
pub use rustc_lint_defs::{pluralize, Applicability};
-use rustc_serialize::json::Json;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::source_map::SourceMap;
+use rustc_span::HashStableContext;
use rustc_span::{Loc, Span};
use std::borrow::Cow;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
use std::num::NonZeroUsize;
use std::panic;
use std::path::Path;
}
}
-#[derive(Clone, Debug, PartialEq, Default)]
-pub struct ToolMetadata(pub Option<Json>);
-
-impl ToolMetadata {
- fn new(json: Json) -> Self {
- ToolMetadata(Some(json))
- }
-
- fn is_set(&self) -> bool {
- self.0.is_some()
- }
-}
-
-impl Hash for ToolMetadata {
- fn hash<H: Hasher>(&self, _state: &mut H) {}
-}
-
-// Doesn't really need to round-trip
-impl<D: Decoder> Decodable<D> for ToolMetadata {
- fn decode(_d: &mut D) -> Self {
- ToolMetadata(None)
- }
-}
-
-impl<S: Encoder> Encodable<S> for ToolMetadata {
- fn encode(&self, e: &mut S) -> Result<(), S::Error> {
- match &self.0 {
- None => e.emit_unit(),
- Some(json) => json.encode(e),
- }
- }
-}
-
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
pub struct CodeSuggestion {
/// Each substitute can have multiple variants due to multiple
/// which are useful for users but not useful for
/// tools like rustfix
pub applicability: Applicability,
- /// Tool-specific metadata
- pub tool_metadata: ToolMetadata,
}
#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
/// Useful type to use with `Result<>` indicate that an error has already
/// been reported to the user, so no need to continue checking.
#[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(HashStable_Generic)]
pub struct ErrorGuaranteed(());
impl ErrorGuaranteed {
ErrorGuaranteed(())
}
}
-
-rustc_data_structures::impl_stable_hash_via_hash!(ErrorGuaranteed);
-use crate::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use crate::def_id::DefId;
use crate::hir;
use rustc_ast as ast;
pub fn descr(self, def_id: DefId) -> &'static str {
match self {
DefKind::Fn => "function",
- DefKind::Mod if def_id.index == CRATE_DEF_INDEX && def_id.krate != LOCAL_CRATE => {
- "crate"
- }
+ DefKind::Mod if def_id.is_crate_root() && !def_id.is_local() => "crate",
DefKind::Mod => "module",
DefKind::Static(..) => "static",
DefKind::Enum => "enum",
}
}
- /// Retrieves the root definition.
- pub fn get_root_def(&self) -> LocalDefId {
- LocalDefId { local_def_index: CRATE_DEF_INDEX }
- }
-
/// Adds a definition with a parent definition.
pub fn create_def(
&mut self,
-use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use crate::def_id::{LocalDefId, CRATE_DEF_ID};
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
/// integers starting at zero, so a mapping that maps all or most nodes within
/// an "item-like" to something else can be implemented by a `Vec` instead of a
/// tree or hash map.
+ #[derive(HashStable_Generic)]
pub struct ItemLocalId { .. }
}
-rustc_data_structures::impl_stable_hash_via_hash!(ItemLocalId);
+
impl ItemLocalId {
/// Signal local id which should never be used.
pub const INVALID: ItemLocalId = ItemLocalId::MAX;
}
-/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`.
-pub const CRATE_HIR_ID: HirId = HirId {
- owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
- local_id: ItemLocalId::from_u32(0),
-};
+/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
+pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::from_u32(0) };
// Avoid fetching the variance if we are in an invariant
// context; no need, and it can induce dependency cycles
// (e.g., #41849).
- relate::relate_substs(self, None, a_subst, b_subst)
+ relate::relate_substs(self, a_subst, b_subst)
} else {
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
- relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst)
+ relate::relate_substs_with_variances(
+ self,
+ item_def_id,
+ &opt_variances,
+ a_subst,
+ b_subst,
+ )
}
}
// performing trait matching (which then performs equality
// unification).
- relate::relate_substs(self, None, a_subst, b_subst)
+ relate::relate_substs(self, a_subst, b_subst)
}
fn relate_with_variance<T: Relate<'tcx>>(
rustc_feature = { path = "../rustc_feature" }
rustc_index = { path = "../rustc_index" }
rustc_session = { path = "../rustc_session" }
-rustc_serialize = { path = "../rustc_serialize" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_infer = { path = "../rustc_infer" }
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_serialize::json::Json;
-use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
db.span_label(span, "the attribute is introduced here");
}
- BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => {
- let json = match loc {
- ExternDepSpec::Json(json) => {
- db.help(&format!("remove unnecessary dependency `{}`", krate));
- json
- }
- ExternDepSpec::Raw(raw) => {
- db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw));
- db.span_suggestion_with_style(
- DUMMY_SP,
- "raw extern location",
- raw.clone(),
- Applicability::Unspecified,
- SuggestionStyle::CompletelyHidden,
- );
- Json::String(raw)
- }
- };
- db.tool_only_suggestion_with_metadata(
- "json extern location",
- Applicability::Unspecified,
- json
- );
- }
BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
db.note(¬e);
}
use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_error_messages::MultiSpan;
+use rustc_hir::HashStableContext;
use rustc_hir::HirId;
-use rustc_serialize::json::Json;
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, Span, Symbol};
use rustc_target::spec::abi::Abi;
/// Setting for how to handle a lint.
///
/// See: <https://doc.rust-lang.org/rustc/lints/levels.html>
-#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, HashStable_Generic)]
pub enum Level {
/// The `allow` level will not issue any message.
Allow,
Forbid,
}
-rustc_data_structures::impl_stable_hash_via_hash!(Level);
-
impl Level {
/// Converts a level to a lower-case string.
pub fn as_str(self) -> &'static str {
}
}
-// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
-#[derive(PartialEq, Debug)]
-pub enum ExternDepSpec {
- Json(Json),
- Raw(String),
-}
-
// This could be a closure, but then implementing derive trait
// becomes hacky (and it gets allocated).
#[derive(Debug)]
UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
PatternsInFnsWithoutBody(Span, Ident),
LegacyDeriveHelpers(Span),
- ExternDepSpec(String, ExternDepSpec),
ProcMacroBackCompat(String),
OrPatternsBackCompat(Span, String),
ReservedPrefix(Span),
use rustc_hir::definitions::Definitions;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::TyCtxt;
-use rustc_serialize::json::ToJson;
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn};
-use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
+use rustc_session::lint;
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
use rustc_target::spec::{PanicStrategy, TargetTriple};
use proc_macro::bridge::client::ProcMacro;
-use std::collections::BTreeMap;
use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
continue;
}
- let diag = match self.sess.opts.extern_dep_specs.get(name) {
- Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
- None => {
- // If we don't have a specific location, provide a json encoding of the `--extern`
- // option.
- let meta: BTreeMap<String, String> =
- std::iter::once(("name".to_string(), name.to_string())).collect();
- BuiltinLintDiagnostics::ExternDepSpec(
- name.clone(),
- ExternDepSpec::Json(meta.to_json()),
- )
- }
- };
- self.sess.parse_sess.buffer_lint_with_diagnostic(
+ self.sess.parse_sess.buffer_lint(
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
span,
ast::CRATE_NODE_ID,
name,
self.local_crate_name,
name),
- diag,
);
}
}
use rustc_middle::thir;
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::GeneratorDiagnosticData;
use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
use rustc_serialize::{opaque, Decodable, Decoder};
use rustc_session::cstore::{
.collect()
})
}
+
+ fn get_generator_diagnostic_data(
+ self,
+ tcx: TyCtxt<'tcx>,
+ id: DefIndex,
+ ) -> Option<GeneratorDiagnosticData<'tcx>> {
+ self.root
+ .tables
+ .generator_diagnostic_data
+ .get(self, id)
+ .map(|param| param.decode((self, tcx)))
+ .map(|generator_data| GeneratorDiagnosticData {
+ generator_interior_types: generator_data.generator_interior_types,
+ hir_owner: generator_data.hir_owner,
+ nodes_types: generator_data.nodes_types,
+ adjustments: generator_data.adjustments,
+ })
+ }
+
+ fn get_may_have_doc_links(self, index: DefIndex) -> bool {
+ self.root.tables.may_have_doc_links.get(self, index).is_some()
+ }
}
impl CrateMetadata {
use rustc_ast as ast;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
crate_extern_paths => { cdata.source().paths().cloned().collect() }
expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) }
+ generator_diagnostic_data => { cdata.get_generator_diagnostic_data(tcx, def_id.index) }
}
pub(in crate::rmeta) fn provide(providers: &mut Providers) {
continue;
}
- bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
+ bfs_queue.push_back(cnum.as_def_id());
}
let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
) -> impl Iterator<Item = DefId> + '_ {
self.get_crate_data(cnum).get_all_incoherent_impls()
}
+
+ pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
+ self.get_crate_data(def_id.krate).get_may_have_doc_links(def_id.index)
+ }
}
impl CrateStore for CStore {
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ fn encode_attrs(&mut self, def_id: DefId) {
+ let attrs = self.tcx.get_attrs(def_id);
+ record!(self.tables.attributes[def_id] <- attrs);
+ if attrs.iter().any(|attr| attr.may_have_doc_links()) {
+ self.tables.may_have_doc_links.set(def_id.index, ());
+ }
+ }
+
fn encode_def_ids(&mut self) {
if self.is_proc_macro {
return;
let Some(def_kind) = def_kind else { continue };
self.tables.opt_def_kind.set(def_id.index, def_kind);
record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
+ self.encode_attrs(def_id);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
let def_id = self.tcx.hir().local_def_id(hir_id);
debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
-
// NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
// including on the signature, which is inferred in `typeck.
- let ty = self.tcx.typeck(def_id).node_type(hir_id);
-
+ let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id);
+ let ty = typeck_result.node_type(hir_id);
match ty.kind() {
ty::Generator(..) => {
let data = self.tcx.generator_kind(def_id).unwrap();
+ let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data();
record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator);
record!(self.tables.generator_kind[def_id.to_def_id()] <- data);
+ record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data);
}
ty::Closure(..) => {
let hir = tcx.hir();
let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
- let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX));
+ let stability = tcx.lookup_stability(CRATE_DEF_ID);
let macros =
self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
- record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
+ self.encode_attrs(LOCAL_CRATE.as_def_id());
record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
if let Some(stability) = stability {
record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
let def_id = id.to_def_id();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
- record!(self.tables.attributes[def_id] <- attrs);
+ self.encode_attrs(def_id);
record!(self.tables.def_keys[def_id] <- def_key);
record!(self.tables.def_ident_span[def_id] <- span);
record!(self.tables.def_span[def_id] <- span);
use rustc_middle::thir;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::GeneratorDiagnosticData;
use rustc_middle::ty::{self, ReprOptions, Ty};
use rustc_serialize::opaque::Encoder;
use rustc_session::config::SymbolManglingVersion;
def_keys: Table<DefIndex, Lazy<DefKey>>,
def_path_hashes: Table<DefIndex, DefPathHash>,
proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
+ generator_diagnostic_data: Table<DefIndex, Lazy<GeneratorDiagnosticData<'tcx>>>,
+ may_have_doc_links: Table<DefIndex, ()>,
}
#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)]
}
}
+impl FixedSizeEncoding for Option<()> {
+ type ByteArray = [u8; 1];
+
+ #[inline]
+ fn from_bytes(b: &[u8; 1]) -> Self {
+ (b[0] != 0).then(|| ())
+ }
+
+ #[inline]
+ fn write_to_bytes(self, b: &mut [u8; 1]) {
+ b[0] = self.is_some() as u8
+ }
+}
+
// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
// generic `Lazy<T>` impl, but in the general case we might not need / want to
// fit every `usize` in `u32`.
use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_query_system::dep_graph::FingerprintStyle;
#[inline(always)]
fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
- let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
+ let def_id = self.as_def_id();
def_id.to_fingerprint(tcx)
}
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
};
}
- let is_staged_api =
- self.lookup_stability(DefId { index: CRATE_DEF_INDEX, ..def_id }).is_some();
+ let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return EvalResult::Allow;
}
/// `get_bytes_with_uninit_and_ptr` instead,
///
/// This function also guarantees that the resulting pointer will remain stable
- /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+ /// even when new allocations are pushed to the `HashMap`. `mem_copy_repeatedly` relies
/// on that.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
let val = match val {
ScalarMaybeUninit::Scalar(scalar) => scalar,
ScalarMaybeUninit::Uninit => {
- self.mark_init(range, false);
- return Ok(());
+ return self.write_uninit(cx, range);
}
};
Ok(())
}
+
+ /// Write "uninit" to the given memory range.
+ pub fn write_uninit(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+ self.mark_init(range, false);
+ self.clear_relocations(cx, range)?;
+ return Ok(());
+ }
}
/// Relocations.
if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
return Err(AllocError::PartialPointerOverwrite(first));
}
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {first:?}..{start:?}."
+ );
self.init_mask.set_range(first, start, false);
}
if last > end {
last - cx.data_layout().pointer_size,
));
}
+ warn!(
+ "Partial pointer overwrite! De-initializing memory at offsets {end:?}..{last:?}."
+ );
self.init_mask.set_range(end, last, false);
}
// Forget all the relocations.
+ // Since relocations do not overlap, we know that removing until `last` (exclusive) is fine,
+ // i.e., this will not remove any other relocations just after the ones we care about.
self.relocations.0.remove_range(first..last);
Ok(())
}
/// A partial, owned list of relocations to transfer into another allocation.
+///
+/// Offsets are already adjusted to the destination allocation.
pub struct AllocationRelocations<Tag> {
- relative_relocations: Vec<(Size, Tag)>,
+ dest_relocations: Vec<(Size, Tag)>,
}
impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
) -> AllocationRelocations<Tag> {
let relocations = self.get_relocations(cx, src);
if relocations.is_empty() {
- return AllocationRelocations { relative_relocations: Vec::new() };
+ return AllocationRelocations { dest_relocations: Vec::new() };
}
let size = src.size;
let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
+ // If `count` is large, this is rather wasteful -- we are allocating a big array here, which
+ // is mostly filled with redundant information since it's just N copies of the same `Tag`s
+ // at slightly adjusted offsets. The reason we do this is so that in `mark_relocation_range`
+ // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces
+ // the right sequence of relocations for all N copies.
for i in 0..count {
new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
// compute offset for current repetition
}));
}
- AllocationRelocations { relative_relocations: new_relocations }
+ AllocationRelocations { dest_relocations: new_relocations }
}
/// Applies a relocation copy.
/// The affected range, as defined in the parameters to `prepare_relocation_copy` is expected
/// to be clear of relocations.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
pub fn mark_relocation_range(&mut self, relocations: AllocationRelocations<Tag>) {
- self.relocations.0.insert_presorted(relocations.relative_relocations);
+ self.relocations.0.insert_presorted(relocations.dest_relocations);
}
}
})
}
- pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+ fn mark_init(&mut self, range: AllocRange, is_init: bool) {
if range.size.bytes() == 0 {
return;
}
}
/// Applies multiple instances of the run-length encoding to the initialization mask.
+ ///
+ /// This is dangerous to use as it can violate internal `Allocation` invariants!
+ /// It only exists to support an efficient implementation of `mem_copy_repeatedly`.
pub fn mark_compressed_init_range(
&mut self,
defined: &InitMaskCompressed,
}
static_assert_size!(Pointer, 16);
+// `Option<Tag>` pointers are also passed around quite a bit
+// (but not stored in permanent machine state).
+static_assert_size!(Pointer<Option<AllocId>>, 16);
// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
}
impl<Tag> Pointer<Option<Tag>> {
+ /// Convert this pointer that *might* have a tag into a pointer that *definitely* has a tag, or
+ /// an absolute address.
+ ///
+ /// This is rarely what you want; call `ptr_try_get_alloc_id` instead.
pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
match self.provenance {
Some(tag) => Ok(Pointer::new(tag, self.offset)),
None => Err(self.offset),
}
}
+
+ /// Returns the absolute address the pointer points to.
+ /// Only works if Tag::OFFSET_IS_ADDR is true!
+ pub fn addr(self) -> Size
+ where
+ Tag: Provenance,
+ {
+ assert!(Tag::OFFSET_IS_ADDR);
+ self.offset
+ }
}
impl<Tag> Pointer<Option<Tag>> {
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId};
use rustc_session::Session;
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
let mut body = Body {
phase: MirPhase::Built,
- source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
+ source: MirSource::item(CRATE_DEF_ID.to_def_id()),
basic_blocks,
source_scopes: IndexVec::new(),
generator: None,
}
if let Some(&tag) = alloc.relocations().get(&i) {
// Memory with a relocation must be defined
+ assert!(alloc.init_mask().is_range_initialized(i, i + ptr_size).is_ok());
let j = i.bytes_usize();
let offset = alloc
.inspect_with_uninit_and_ptr_outside_interpreter(j..j + ptr_size.bytes_usize());
eval_always
desc { "computing the backend features for CLI flags" }
}
+
+ query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
}
static_assert_size!(ConstS<'_>, 48);
impl<'tcx> Const<'tcx> {
+ #[inline]
pub fn ty(self) -> Ty<'tcx> {
self.0.ty
}
+ #[inline]
pub fn val(self) -> ConstKind<'tcx> {
self.0.val
}
pub expr: Option<hir::HirId>,
}
+// This type holds diagnostic information on generators and async functions across crate boundaries
+// and is used to provide better error messages
+#[derive(TyEncodable, TyDecodable, Clone, Debug, HashStable)]
+pub struct GeneratorDiagnosticData<'tcx> {
+ pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
+ pub hir_owner: DefId,
+ pub nodes_types: ItemLocalMap<Ty<'tcx>>,
+ pub adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
+}
+
#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
pub struct TypeckResults<'tcx> {
/// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.node_types }
}
+ pub fn get_generator_diagnostic_data(&self) -> GeneratorDiagnosticData<'tcx> {
+ let generator_interior_type = self.generator_interior_types.map_bound_ref(|vec| {
+ vec.iter()
+ .map(|item| {
+ GeneratorInteriorTypeCause {
+ ty: item.ty,
+ span: item.span,
+ scope_span: item.scope_span,
+ yield_span: item.yield_span,
+ expr: None, //FIXME: Passing expression over crate boundaries is impossible at the moment
+ }
+ })
+ .collect::<Vec<_>>()
+ });
+ GeneratorDiagnosticData {
+ generator_interior_types: generator_interior_type,
+ hir_owner: self.hir_owner.to_def_id(),
+ nodes_types: self.node_types.clone(),
+ adjustments: self.adjustments.clone(),
+ }
+ }
+
pub fn node_type(&self, id: hir::HirId) -> Ty<'tcx> {
self.node_type_opt(id).unwrap_or_else(|| {
bug!("node_type: no type for node `{}`", tls::with(|tcx| tcx.hir().node_to_string(id)))
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_ID};
use rustc_hir::Node;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
- Lift, OnDiskCache, TyCtxt, TypeckResults, UserType, UserTypeAnnotationIndex,
+ CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+ GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
+ UserTypeAnnotationIndex,
};
pub use self::instance::{Instance, InstanceDef};
pub use self::list::List;
pub fn from_hir(visibility: &hir::Visibility<'_>, id: hir::HirId, tcx: TyCtxt<'_>) -> Self {
match visibility.node {
hir::VisibilityKind::Public => Visibility::Public,
- hir::VisibilityKind::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
+ hir::VisibilityKind::Crate(_) => Visibility::Restricted(CRATE_DEF_ID.to_def_id()),
hir::VisibilityKind::Restricted { ref path, .. } => match path.res {
// If there is no resolution, `resolve` will have already reported an error, so
// assume that the visibility is public to avoid reporting more privacy errors.
}
fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
- if def_id.index == CRATE_DEF_INDEX {
- Some(self.crate_name(def_id.krate))
+ if let Some(cnum) = def_id.as_crate_root() {
+ Some(self.crate_name(cnum))
} else {
let def_key = self.def_key(def_id);
match def_key.disambiguated_data.data {
use rustc_data_structures::sso::SsoHashSet;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
-use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
use rustc_session::config::TrimmedDefPaths;
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
// If `def_id` is a direct or injected extern crate, return the
// path to the crate followed by the path to the item within the crate.
- if def_id.index == CRATE_DEF_INDEX {
- let cnum = def_id.krate;
-
+ if let Some(cnum) = def_id.as_crate_root() {
if cnum == LOCAL_CRATE {
return Ok((self.path_crate(cnum)?, true));
}
ty::BrNamed(_, _) => br.kind,
ty::BrAnon(i) => {
let name = region_map[&(i + 1)];
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
ty::BrEnv => {
let name = region_map[&0];
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
};
self.tcx.mk_region(ty::ReLateBound(
}
};
do_continue(&mut self, name);
- ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name)
+ ty::BrNamed(CRATE_DEF_ID.to_def_id(), name)
}
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind }))
let mut seen_defs: DefIdSet = Default::default();
for &cnum in tcx.crates(()).iter() {
- let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let def_id = cnum.as_def_id();
// Ignore crates that are not direct dependencies.
match tcx.extern_crate(def_id) {
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
use rustc_session::utils::NativeLibKind;
use rustc_session::Limits;
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-
-use rustc_ast as ast;
-use rustc_attr as attr;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
let tcx = self.tcx();
let opt_variances = tcx.variances_of(item_def_id);
- relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst)
+ relate_substs_with_variances(self, item_def_id, opt_variances, a_subst, b_subst)
}
/// Switch variance for the purpose of relating `a` and `b`.
}
}
+#[inline]
pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
- variances: Option<(DefId, &[ty::Variance])>,
+ a_subst: SubstsRef<'tcx>,
+ b_subst: SubstsRef<'tcx>,
+) -> RelateResult<'tcx, SubstsRef<'tcx>> {
+ relation.tcx().mk_substs(iter::zip(a_subst, b_subst).map(|(a, b)| {
+ relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)
+ }))
+}
+
+pub fn relate_substs_with_variances<'tcx, R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ ty_def_id: DefId,
+ variances: &[ty::Variance],
a_subst: SubstsRef<'tcx>,
b_subst: SubstsRef<'tcx>,
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
let tcx = relation.tcx();
- let mut cached_ty = None;
+ let mut cached_ty = None;
let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| {
- let (variance, variance_info) = match variances {
- Some((ty_def_id, variances)) => {
- let variance = variances[i];
- let variance_info = if variance == ty::Invariant {
- let ty = *cached_ty
- .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
- ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
- } else {
- ty::VarianceDiagInfo::default()
- };
- (variance, variance_info)
- }
- None => (ty::Invariant, ty::VarianceDiagInfo::default()),
+ let variance = variances[i];
+ let variance_info = if variance == ty::Invariant {
+ let ty = *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+ ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
+ } else {
+ ty::VarianceDiagInfo::default()
};
relation.relate_with_variance(variance, variance_info, a, b)
});
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::TraitRef { def_id: a.def_id, substs })
}
}
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs })
}
}
(&ty::Opaque(a_def_id, a_substs), &ty::Opaque(b_def_id, b_substs))
if a_def_id == b_def_id =>
{
- let substs = relate_substs(relation, None, a_substs, b_substs)?;
+ let substs = relate_substs(relation, a_substs, b_substs)?;
Ok(tcx.mk_opaque(a_def_id, substs))
}
a: ty::ClosureSubsts<'tcx>,
b: ty::ClosureSubsts<'tcx>,
) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::ClosureSubsts { substs })
}
}
a: ty::GeneratorSubsts<'tcx>,
b: ty::GeneratorSubsts<'tcx>,
) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> {
- let substs = relate_substs(relation, None, a.substs, b.substs)?;
+ let substs = relate_substs(relation, a.substs, b.substs)?;
Ok(ty::GeneratorSubsts { substs })
}
}
a: SubstsRef<'tcx>,
b: SubstsRef<'tcx>,
) -> RelateResult<'tcx, SubstsRef<'tcx>> {
- relate_substs(relation, None, a, b)
+ relate_substs(relation, a, b)
}
}
use rustc_data_structures::functor::IdFunctor;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
use rustc_index::vec::{Idx, IndexVec};
use std::fmt;
match *self {
ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
ty::BrNamed(did, name) => {
- if did.index == CRATE_DEF_INDEX {
+ if did.is_crate_root() {
write!(f, "BrNamed({})", name)
} else {
write!(f, "BrNamed({:?}, {})", did, name)
func: fun,
args,
cleanup: None,
- // FIXME(varkor): replace this with an uninhabitedness-based check.
- // This requires getting access to the current module to call
- // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
- destination: if expr.ty.is_never() {
+ // The presence or absence of a return edge affects control-flow sensitive
+ // MIR checks and ultimately whether code is accepted or not. We can only
+ // omit the return edge if a return type is visibly uninhabited to a module
+ // that makes the call.
+ destination: if this.tcx.is_ty_uninhabited_from(
+ this.parent_module,
+ expr.ty,
+ this.param_env,
+ ) {
None
} else {
Some((destination, success))
def_id: DefId,
hir_id: hir::HirId,
+ parent_module: DefId,
check_overflow: bool,
fn_span: Span,
arg_count: usize,
);
let lint_level = LintLevel::Explicit(hir_id);
+ let param_env = tcx.param_env(def.did);
let mut builder = Builder {
thir,
tcx,
infcx,
typeck_results: tcx.typeck_opt_const_arg(def),
region_scope_tree: tcx.region_scope_tree(def.did),
- param_env: tcx.param_env(def.did),
+ param_env,
def_id: def.did.to_def_id(),
hir_id,
+ parent_module: tcx.parent_module(hir_id).to_def_id(),
check_overflow,
cfg: CFG { basic_blocks: IndexVec::new() },
fn_span: span,
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathDataName;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::exported_symbols::SymbolExportLevel;
let mut cgu_def_id = None;
// Walk backwards from the item we want to find the module for.
loop {
- if current_def_id.index == CRATE_DEF_INDEX {
+ if current_def_id.is_crate_root() {
if cgu_def_id.is_none() {
// If we have not found a module yet, take the crate root.
- cgu_def_id = Some(DefId { krate: def_id.krate, index: CRATE_DEF_INDEX });
+ cgu_def_id = Some(def_id.krate.as_def_id());
}
break;
} else if tcx.def_kind(current_def_id) == DefKind::Mod {
use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_session::config::{CrateType, EntryFnType};
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
-struct EntryContext<'a, 'tcx> {
- session: &'a Session,
-
- map: Map<'tcx>,
+struct EntryContext<'tcx> {
+ tcx: TyCtxt<'tcx>,
/// The function that has attribute named `main`.
attr_main_fn: Option<(LocalDefId, Span)>,
non_main_fns: Vec<Span>,
}
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
+impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
- let def_key = self.map.def_key(item.def_id);
- let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
+ let at_root = self.tcx.local_parent(item.def_id) == Some(CRATE_DEF_ID);
find_item(item, self, at_root);
}
return None;
}
- let mut ctxt = EntryContext {
- session: tcx.sess,
- map: tcx.hir(),
- attr_main_fn: None,
- start_fn: None,
- non_main_fns: Vec::new(),
- };
+ let mut ctxt =
+ EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
tcx.hir().visit_all_item_likes(&mut ctxt);
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
// (with `ast::Item`), so make sure to keep them in sync.
-fn entry_point_type(ctxt: &EntryContext<'_, '_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
- let attrs = ctxt.map.attrs(item.hir_id());
- if ctxt.session.contains_name(attrs, sym::start) {
+fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
+ let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+ if ctxt.tcx.sess.contains_name(attrs, sym::start) {
EntryPointType::Start
- } else if ctxt.session.contains_name(attrs, sym::rustc_main) {
+ } else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
.emit();
}
-fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
+fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
match entry_point_type(ctxt, item, at_root) {
EntryPointType::None => (),
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
- let attrs = ctxt.map.attrs(item.hir_id());
- if let Some(attr) = ctxt.session.find_by_name(attrs, sym::start) {
- throw_attr_err(&ctxt.session, attr.span, "start");
+ let attrs = ctxt.tcx.hir().attrs(item.hir_id());
+ if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
+ throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
}
- if let Some(attr) = ctxt.session.find_by_name(attrs, sym::rustc_main) {
- throw_attr_err(&ctxt.session, attr.span, "rustc_main");
+ if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) {
+ throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main");
}
}
EntryPointType::MainNamed => (),
ctxt.attr_main_fn = Some((item.def_id, item.span));
} else {
struct_span_err!(
- ctxt.session,
+ ctxt.tcx.sess,
item.span,
E0137,
"multiple functions with a `#[main]` attribute"
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.def_id, item.span));
} else {
- struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
+ struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
.span_label(item.span, "multiple `start` functions")
.emit();
}
}
-fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
+fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
if let Some((def_id, _)) = visitor.start_fn {
Some((def_id.to_def_id(), EntryFnType::Start))
} else if let Some((def_id, _)) = visitor.attr_main_fn {
}
}
-fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
+fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
let sp = tcx.def_span(CRATE_DEF_ID);
if *tcx.sess.parse_sess.reached_eof.borrow() {
// There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lock;
use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{HirId, ItemLocalId};
self.owner = Some(owner);
walk(self);
- if owner.local_def_index == CRATE_DEF_INDEX {
+ if owner == CRATE_DEF_ID {
return;
}
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
return;
};
- let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let def_id = cnum.as_def_id();
self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
}
use measureme::{StringComponent, StringId};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_middle::ty::{TyCtxt, WithOptConstParam};
use rustc_query_system::query::QueryCache;
&self,
builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
) -> StringId {
- builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
+ builder.def_id_to_string_id(self.as_def_id())
}
}
use rustc_expand::base::SyntaxExtension;
use rustc_expand::expand::AstFragment;
use rustc_hir::def::{self, *};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_metadata::creader::LoadedMacro;
use rustc_middle::bug;
use rustc_middle::metadata::ModChild;
let parent = def_key.parent.map(|index| {
self.get_nearest_non_block_module(DefId { index, krate: def_id.krate })
});
- let name = if def_id.index == CRATE_DEF_INDEX {
- self.cstore().crate_name(def_id.krate)
+ let name = if let Some(cnum) = def_id.as_crate_root() {
+ self.cstore().crate_name(cnum)
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
match vis.kind {
ast::VisibilityKind::Public => Ok(ty::Visibility::Public),
ast::VisibilityKind::Crate(..) => {
- Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
+ Ok(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))
}
ast::VisibilityKind::Inherited => {
Ok(match self.parent_scope.module.kind {
let mut ctor_vis = if vis == ty::Visibility::Public
&& self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
{
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
} else {
vis
};
root_span: span,
span,
module_path: Vec::new(),
- vis: Cell::new(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))),
+ vis: Cell::new(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())),
used: Cell::new(false),
})
};
let vis = if is_macro_export {
ty::Visibility::Public
} else {
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
};
let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
self.r.set_binding_parent_module(binding, parent_scope.module);
let ctor_vis = if vis == ty::Visibility::Public
&& self.r.session.contains_name(&variant.attrs, sym::non_exhaustive)
{
- ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
+ ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id())
} else {
vis
};
use rustc_feature::BUILTIN_ATTRIBUTES;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_middle::bug;
use rustc_middle::ty::DefIdTree;
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
- let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
+ let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
}));
}
use rustc_errors::DiagnosticId;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::{PrimTy, TraitCandidate};
use rustc_middle::ty::DefIdTree;
use rustc_middle::{bug, span_bug};
// trait to resolve. In that case, we leave the `B`
// segment to be resolved by type-check.
return Ok(Some(PartialRes::with_unresolved_segments(
- Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)),
+ Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id()),
path.len(),
)));
}
use rustc_hir as hir;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::PrimTy;
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
}
})
.collect::<Vec<_>>();
- let crate_def_id = DefId::local(CRATE_DEF_INDEX);
+ let crate_def_id = CRATE_DEF_ID.to_def_id();
if candidates.is_empty() && is_expected(Res::Def(DefKind::Enum, crate_def_id)) {
let mut enum_candidates: Vec<_> = self
.r
names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
self.r.crate_loader.maybe_process_path_extern(ident.name).and_then(
|crate_id| {
- let crate_mod = Res::Def(
- DefKind::Mod,
- DefId { krate: crate_id, index: CRATE_DEF_INDEX },
- );
+ let crate_mod =
+ Res::Def(DefKind::Mod, crate_id.as_def_id());
if filter_fn(crate_mod) {
Some(TypoSuggestion::typo_from_res(
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::TraitCandidate;
use rustc_index::vec::IndexVec;
NameBindingKind::Module(&ModuleData {
kind: ModuleKind::Def(DefKind::Mod, def_id, _),
..
- }) => def_id.index == CRATE_DEF_INDEX,
+ }) => def_id.is_crate_root(),
_ => false,
}
}
);
let definitions = Definitions::new(session.local_stable_crate_id(), krate.spans.inner_span);
- let root = definitions.get_root_def();
let mut visibilities = FxHashMap::default();
visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public);
let mut def_id_to_node_id = IndexVec::default();
- assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
+ assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID);
let mut node_id_to_def_id = FxHashMap::default();
- node_id_to_def_id.insert(CRATE_NODE_ID, root);
+ node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID);
let mut invocation_parents = FxHashMap::default();
- invocation_parents.insert(LocalExpnId::ROOT, (root, ImplTraitContext::Existential));
+ invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential));
let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = session
.opts
pub use crate::options::*;
-use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use crate::{early_error, early_warn, Session};
+use crate::{lint, HashStableContext};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::impl_stable_hash_via_hash;
+use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
-use rustc_serialize::json;
-
use crate::parse::{CrateCheckConfig, CrateConfig};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
Full,
}
-#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
pub enum OptLevel {
No, // -O0
Less, // -O1
SizeMin, // -Oz
}
-impl_stable_hash_via_hash!(OptLevel);
-
/// This is what the `LtoCli` values get mapped to after resolving defaults and
/// and taking other command line options into account.
///
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum SymbolManglingVersion {
Legacy,
V0,
}
-impl_stable_hash_via_hash!(SymbolManglingVersion);
-
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum DebugInfo {
None,
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
Bitcode,
DepInfo,
}
-impl_stable_hash_via_hash!(OutputType);
+impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
+ type KeyType = Self;
+
+ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+ *self
+ }
+}
impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
/// should only depend on the output types, not the paths they're written to.
-#[derive(Clone, Debug, Hash)]
+#[derive(Clone, Debug, Hash, HashStable_Generic)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
impl OutputTypes {
#[derive(Clone)]
pub struct Externs(BTreeMap<String, ExternEntry>);
-#[derive(Clone)]
-pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
-
#[derive(Clone, Debug)]
pub struct ExternEntry {
pub location: ExternLocation,
ExactPaths(BTreeSet<CanonicalizedPath>),
}
-/// Supplied source location of a dependency - for example in a build specification
-/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
-/// a file and line, then the build system can specify that. On the other hand, it may
-/// make more sense to have an arbitrary raw string.
-#[derive(Clone, PartialEq)]
-pub enum ExternDepSpec {
- /// Raw string
- Raw(String),
- /// Raw data in json format
- Json(json::Json),
-}
-
-impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
- fn from(from: &'a ExternDepSpec) -> Self {
- match from {
- ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
- ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
- }
- }
-}
-
impl Externs {
/// Used for testing.
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
}
}
-impl ExternDepSpecs {
- pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
- ExternDepSpecs(data)
- }
-
- pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
- self.0.get(key)
- }
-}
-
-impl fmt::Display for ExternDepSpec {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- ExternDepSpec::Raw(raw) => fmt.write_str(raw),
- ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
- }
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PrintRequest {
FileNames,
}
}
-#[derive(Clone, Hash, Debug)]
+#[derive(Clone, Hash, Debug, HashStable_Generic)]
pub struct OutputFilenames {
pub out_directory: PathBuf,
filestem: String,
pub outputs: OutputTypes,
}
-impl_stable_hash_via_hash!(OutputFilenames);
-
pub const RLINK_EXT: &str = "rlink";
pub const RUST_CGU_EXT: &str = "rcgu";
pub const DWARF_OBJECT_EXT: &str = "dwo";
cg: Default::default(),
error_format: ErrorOutputType::default(),
externs: Externs(BTreeMap::new()),
- extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
crate_name: None,
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
}
// The type of entry function, so users can have their own entry functions
-#[derive(Copy, Clone, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
pub enum EntryFnType {
Main,
Start,
}
-impl_stable_hash_via_hash!(EntryFnType);
-
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum CrateType {
Executable,
Dylib,
ProcMacro,
}
-impl_stable_hash_via_hash!(CrateType);
-
impl CrateType {
/// When generated, is this crate type an archive?
pub fn is_archive(&self) -> bool {
"Specify where an external rust library is located",
"NAME[=PATH]",
),
- opt::multi_s(
- "",
- "extern-location",
- "Location where an external crate dependency is specified",
- "NAME=LOCATION",
- ),
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set internal debugging options", "FLAG"),
opt::opt_s(
Externs(externs)
}
-fn parse_extern_dep_specs(
- matches: &getopts::Matches,
- debugging_opts: &DebuggingOptions,
- error_format: ErrorOutputType,
-) -> ExternDepSpecs {
- let is_unstable_enabled = debugging_opts.unstable_options;
- let mut map = BTreeMap::new();
-
- for arg in matches.opt_strs("extern-location") {
- if !is_unstable_enabled {
- early_error(
- error_format,
- "`--extern-location` option is unstable: set `-Z unstable-options`",
- );
- }
-
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().unwrap_or_else(|| {
- early_error(error_format, "`--extern-location` value must not be empty")
- });
- let loc = parts.next().unwrap_or_else(|| {
- early_error(
- error_format,
- &format!("`--extern-location`: specify location for extern crate `{name}`"),
- )
- });
-
- let locparts: Vec<_> = loc.split(':').collect();
- let spec = match &locparts[..] {
- ["raw", ..] => {
- // Don't want `:` split string
- let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
- early_error(error_format, "`--extern-location`: missing `raw` location")
- });
- ExternDepSpec::Raw(raw.to_string())
- }
- ["json", ..] => {
- // Don't want `:` split string
- let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
- early_error(error_format, "`--extern-location`: missing `json` location")
- });
- let json = json::from_str(raw).unwrap_or_else(|_| {
- early_error(
- error_format,
- &format!("`--extern-location`: malformed json location `{raw}`"),
- )
- });
- ExternDepSpec::Json(json)
- }
- [bad, ..] => early_error(
- error_format,
- &format!("unknown location type `{bad}`: use `raw` or `json`"),
- ),
- [] => early_error(error_format, "missing location specification"),
- };
-
- map.insert(name.to_string(), spec);
- }
-
- ExternDepSpecs::new(map)
-}
-
fn parse_remap_path_prefix(
matches: &getopts::Matches,
debugging_opts: &DebuggingOptions,
}
let externs = parse_externs(matches, &debugging_opts, error_format);
- let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
let crate_name = matches.opt_str("crate-name");
error_format,
externs,
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
- extern_dep_specs,
crate_name,
libs,
debug_assertions,
borrowck_mode: BorrowckMode [UNTRACKED],
cg: CodegenOptions [SUBSTRUCT],
externs: Externs [UNTRACKED],
- extern_dep_specs: ExternDepSpecs [UNTRACKED],
crate_name: Option<String> [TRACKED],
/// Indicates how the compiler should treat unstable features.
unstable_features: UnstableFeatures [TRACKED],
pub file_name_str: String,
}
-#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
+#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable, HashStable_Generic)]
pub enum PathKind {
Native,
Crate,
All,
}
-rustc_data_structures::impl_stable_hash_via_hash!(PathKind);
-
impl PathKind {
pub fn matches(&self, kind: PathKind) -> bool {
match (self, kind) {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum NativeLibKind {
/// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC)
Static {
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
-
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub struct NativeLib {
pub name: String,
pub new_name: Option<String>,
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(NativeLib);
-
/// A path that has been canonicalized along with its original, non-canonicalized form
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CanonicalizedPath {
self.as_local().unwrap_or_else(|| panic!("DefId::expect_local: `{:?}` isn't local", self))
}
+ #[inline]
+ pub fn is_crate_root(self) -> bool {
+ self.index == CRATE_DEF_INDEX
+ }
+
+ #[inline]
+ pub fn as_crate_root(self) -> Option<CrateNum> {
+ if self.is_crate_root() { Some(self.krate) } else { None }
+ }
+
+ #[inline]
pub fn is_top_level_module(self) -> bool {
- self.is_local() && self.index == CRATE_DEF_INDEX
+ self.is_local() && self.is_crate_root()
}
}
#[inline]
pub fn is_top_level_module(self) -> bool {
- self.local_def_index == CRATE_DEF_INDEX
+ self == CRATE_DEF_ID
}
}
pub struct OffsetOverflowError;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+#[derive(HashStable_Generic)]
pub enum SourceFileHashAlgorithm {
Md5,
Sha1,
}
}
-rustc_data_structures::impl_stable_hash_via_hash!(SourceFileHashAlgorithm);
-
/// The hash of the on-disk source file used for debug info.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(HashStable_Generic, Encodable, Decodable)]
keyword,
kind,
kreg,
+ kreg0,
label,
label_break_value,
lang,
xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
- k1, k2, k3, k4, k5, k6, k7,
+ k0, k1, k2, k3, k4, k5, k6, k7,
mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
st0, st1, st2, st3, st4, st5, st6, st7,
ymm_reg,
zmm_reg,
kreg,
+ kreg0,
mmx_reg,
x87_reg,
}
}
Self::reg_byte => &[],
Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
- Self::kreg => &[],
+ Self::kreg | Self::kreg0 => &[],
Self::mmx_reg | Self::x87_reg => &[],
}
}
256 => Some(('y', "ymm0")),
_ => Some(('x', "xmm0")),
},
- Self::kreg => None,
+ Self::kreg | Self::kreg0 => None,
Self::mmx_reg | Self::x87_reg => None,
}
}
Self::xmm_reg => Some(('x', "xmm0")),
Self::ymm_reg => Some(('y', "ymm0")),
Self::zmm_reg => Some(('z', "zmm0")),
- Self::kreg => None,
+ Self::kreg | Self::kreg0 => None,
Self::mmx_reg | Self::x87_reg => None,
}
}
avx512f: I8, I16;
avx512bw: I32, I64;
},
+ Self::kreg0 => &[],
Self::mmx_reg | Self::x87_reg => &[],
}
}
zmm29: zmm_reg = ["zmm29", "xmm29", "ymm29"] % x86_64_only,
zmm30: zmm_reg = ["zmm30", "xmm30", "ymm30"] % x86_64_only,
zmm31: zmm_reg = ["zmm31", "xmm31", "ymm31"] % x86_64_only,
+ k0: kreg0 = ["k0"],
k1: kreg = ["k1"],
k2: kreg = ["k2"],
k3: kreg = ["k3"],
"the stack pointer cannot be used as an operand for inline asm",
#error = ["ip", "eip", "rip"] =>
"the instruction pointer cannot be used as an operand for inline asm",
- #error = ["k0"] =>
- "the k0 AVX mask register cannot be used as an operand for inline asm",
}
}
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_middle::hir::map;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
- Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt,
+ TypeFoldable,
};
use rustc_middle::ty::{TypeAndMut, TypeckResults};
use rustc_session::Limit;
Upvar(Span),
}
+// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// the local crate being compiled or from a foreign crate.
+#[derive(Debug)]
+pub enum GeneratorData<'tcx, 'a> {
+ Local(&'a TypeckResults<'tcx>),
+ Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
+}
+
+impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
+ // Try to get information about variables captured by the generator that matches a type we are
+ // looking for with `ty_matches` function. We uses it to find upvar which causes a failure to
+ // meet an obligation
+ fn try_get_upvar_span<F>(
+ &self,
+ infer_context: &InferCtxt<'a, 'tcx>,
+ generator_did: DefId,
+ ty_matches: F,
+ ) -> Option<GeneratorInteriorOrUpvar>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => {
+ infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+ upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ })
+ })
+ }
+ GeneratorData::Foreign(_) => None,
+ }
+ }
+
+ // Try to get the span of a type being awaited on that matches the type we are looking with the
+ // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+ // obligation
+ fn get_from_await_ty<F>(
+ &self,
+ visitor: AwaitsVisitor,
+ hir: map::Map<'tcx>,
+ ty_matches: F,
+ ) -> Option<Span>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span),
+ GeneratorData::Foreign(generator_diagnostic_data) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(
+ generator_diagnostic_data
+ .adjustments
+ .get(&await_expr.hir_id.local_id)
+ .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
+ .last()
+ .map_or_else::<Ty<'tcx>, _, _>(
+ || {
+ generator_diagnostic_data
+ .nodes_types
+ .get(&await_expr.hir_id.local_id)
+ .cloned()
+ .unwrap_or_else(|| {
+ bug!(
+ "node_type: no type for node `{}`",
+ ty::tls::with(|tcx| tcx
+ .hir()
+ .node_to_string(await_expr.hir_id))
+ )
+ })
+ },
+ |adj| adj.target,
+ ),
+ ))
+ })
+ .map(|expr| expr.span),
+ }
+ }
+
+ /// Get the type, expression, span and optional scope span of all types
+ /// that are live across the yield of this generator
+ fn get_generator_interior_types(
+ &self,
+ ) -> ty::Binder<'tcx, &Vec<GeneratorInteriorTypeCause<'tcx>>> {
+ match self {
+ GeneratorData::Local(typeck_result) => typeck_result.generator_interior_types.as_ref(),
+ GeneratorData::Foreign(generator_diagnostic_data) => {
+ generator_diagnostic_data.generator_interior_types.as_ref()
+ }
+ }
+ }
+
+ // Used to get the source of the data, note we don't have as much information for generators
+ // originated from foreign crates
+ fn is_foreign(&self) -> bool {
+ match self {
+ GeneratorData::Local(_) => false,
+ GeneratorData::Foreign(_) => true,
+ }
+ }
+}
+
// This trait is public to expose the diagnostics methods to clippy.
pub trait InferCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
err: &mut Diagnostic,
interior_or_upvar_span: GeneratorInteriorOrUpvar,
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
- inner_generator_body: Option<&hir::Body<'tcx>>,
+ is_async: bool,
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
.map(|def_id| hir.local_def_id_to_hir_id(def_id))
.and_then(|hir_id| hir.maybe_body_owned_by(hir_id))
.map(|body_id| hir.body(body_id));
+ let is_async = match generator_did.as_local() {
+ Some(_) => generator_body
+ .and_then(|body| body.generator_kind())
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ None => self
+ .tcx
+ .generator_kind(generator_did)
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ };
let mut visitor = AwaitsVisitor::default();
if let Some(body) = generator_body {
visitor.visit_body(body);
// type-checking; otherwise, get them by performing a query. This is needed to avoid
// cycles. If we can't use resolved types because the generator comes from another crate,
// we still provide a targeted error but without all the relevant spans.
- let query_typeck_results;
- let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+ let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
+ Some(GeneratorData::Local(&t))
+ }
_ if generator_did.is_local() => {
- query_typeck_results = self.tcx.typeck(generator_did.expect_local());
- Some(&query_typeck_results)
+ Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())))
}
- _ => None, // Do not ICE on closure typeck (#66868).
+ _ => self
+ .tcx
+ .generator_diagnostic_data(generator_did)
+ .as_ref()
+ .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)),
};
- if let Some(typeck_results) = typeck_results {
- if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
- interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
- if ty_matches(ty::Binder::dummy(upvar_ty)) {
- Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
- } else {
- None
- }
- });
- };
+
+ if let Some(generator_data) = generator_data.as_ref() {
+ interior_or_upvar_span =
+ generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
// The generator interior types share the same binders
if let Some(cause) =
- typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+ generator_data.get_generator_interior_types().skip_binder().iter().find(
|ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(typeck_results.generator_interior_types.rebind(*ty))
+ ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
},
)
{
- // Check to see if any awaited expressions have the target type.
- let from_awaited_ty = visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
- })
- .map(|expr| expr.span);
+ let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
cause;
interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
- };
- } else {
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
+
+ if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
}
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
+ let typeck_results = generator_data.and_then(|generator_data| match generator_data {
+ GeneratorData::Local(typeck_results) => Some(typeck_results),
+ GeneratorData::Foreign(_) => None,
+ });
self.note_obligation_cause_for_async_await(
err,
interior_or_upvar_span,
interior_extra_info,
- generator_body,
+ is_async,
outer_generator,
trait_ref,
target_ty,
err: &mut Diagnostic,
interior_or_upvar_span: GeneratorInteriorOrUpvar,
interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
- inner_generator_body: Option<&hir::Body<'tcx>>,
+ is_async: bool,
outer_generator: Option<DefId>,
trait_pred: ty::TraitPredicate<'tcx>,
target_ty: Ty<'tcx>,
) {
let source_map = self.tcx.sess.source_map();
- let is_async = inner_generator_body
- .and_then(|body| body.generator_kind())
- .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
- .unwrap_or(false);
let (await_or_yield, an_await_or_yield) =
if is_async { ("await", "an await") } else { ("yield", "a yield") };
let future_or_generator = if is_async { "future" } else { "generator" };
use rustc_span::{Span, DUMMY_SP};
use std::collections::BTreeSet;
-use std::iter;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
let mut suggestions = vec![];
let mut types_count = 0;
let mut where_constraints = vec![];
+ let mut already_has_generics_args_suggestion = false;
for (span, assoc_items) in &associated_types {
let mut names: FxHashMap<_, usize> = FxHashMap::default();
for item in assoc_items {
}
}
if potential_assoc_types.len() == assoc_items.len() {
- // Only suggest when the amount of missing associated types equals the number of
- // extra type arguments present, as that gives us a relatively high confidence
- // that the user forgot to give the associated type's name. The canonical
- // example would be trying to use `Iterator<isize>` instead of
- // `Iterator<Item = isize>`.
- for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
- if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
- suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
- }
- }
+ // When the amount of missing associated types equals the number of
+ // extra type arguments present. A suggesting to replace the generic args with
+ // associated types is already emitted.
+ already_has_generics_args_suggestion = true;
} else if let (Ok(snippet), false) =
(tcx.sess.source_map().span_to_snippet(*span), dupes)
{
// the same associated type name.
err.help(where_msg);
}
- if suggestions.len() != 1 {
+ if suggestions.len() != 1 || already_has_generics_args_suggestion {
// We don't need this label if there's an inline suggestion, show otherwise.
for (span, assoc_items) in &associated_types {
let mut names: FxHashMap<_, usize> = FxHashMap::default();
self.tcx.sess,
span,
E0529,
- "expected an array or slice, found `{}`",
- expected_ty
+ "expected an array or slice, found `{expected_ty}`"
);
- if let ty::Ref(_, ty, _) = expected_ty.kind() {
- if let ty::Array(..) | ty::Slice(..) = ty.kind() {
- err.help("the semantics of slice patterns changed recently; see issue #62254");
- }
+ if let ty::Ref(_, ty, _) = expected_ty.kind()
+ && let ty::Array(..) | ty::Slice(..) = ty.kind()
+ {
+ err.help("the semantics of slice patterns changed recently; see issue #62254");
} else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
.any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
+ && let (Some(span), true) = (ti.span, ti.origin_expr)
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
- if let (Some(span), true) = (ti.span, ti.origin_expr) {
- if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
- let applicability = Autoderef::new(
- &self.infcx,
- self.param_env,
- self.body_id,
- span,
- self.resolve_vars_if_possible(ti.expected),
+ let ty = self.resolve_vars_if_possible(ti.expected);
+ let is_slice_or_array_or_vector = self.is_slice_or_array_or_vector(&mut err, snippet.clone(), ty);
+ match is_slice_or_array_or_vector.1.kind() {
+ ty::Adt(adt_def, _)
+ if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
+ || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
+ {
+ // Slicing won't work here, but `.as_deref()` might (issue #91328).
+ err.span_suggestion(
span,
- )
- .find_map(|(ty, _)| {
- match ty.kind() {
- ty::Adt(adt_def, _)
- if self.tcx.is_diagnostic_item(sym::Option, adt_def.did())
- || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) =>
- {
- // Slicing won't work here, but `.as_deref()` might (issue #91328).
- err.span_suggestion(
- span,
- "consider using `as_deref` here",
- format!("{}.as_deref()", snippet),
- Applicability::MaybeIncorrect,
- );
- Some(None)
- }
-
- ty::Slice(..) | ty::Array(..) => {
- Some(Some(Applicability::MachineApplicable))
- }
-
- _ => None,
- }
- })
- .unwrap_or(Some(Applicability::MaybeIncorrect));
-
- if let Some(applicability) = applicability {
- err.span_suggestion(
- span,
- "consider slicing here",
- format!("{}[..]", snippet),
- applicability,
- );
- }
+ "consider using `as_deref` here",
+ format!("{snippet}.as_deref()"),
+ Applicability::MaybeIncorrect,
+ );
}
+ _ => ()
+ }
+ if is_slice_or_array_or_vector.0 {
+ err.span_suggestion(
+ span,
+ "consider slicing here",
+ format!("{snippet}[..]"),
+ Applicability::MachineApplicable,
+ );
}
}
- err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
+ err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`"));
err.emit();
}
+
+ fn is_slice_or_array_or_vector(
+ &self,
+ err: &mut Diagnostic,
+ snippet: String,
+ ty: Ty<'tcx>,
+ ) -> (bool, Ty<'tcx>) {
+ match ty.kind() {
+ ty::Adt(adt_def, _) if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did()) => {
+ (true, ty)
+ }
+ ty::Ref(_, ty, _) => self.is_slice_or_array_or_vector(err, snippet, *ty),
+ ty::Slice(..) | ty::Array(..) => (true, ty),
+ _ => (false, ty),
+ }
+ }
}
use rustc_hir as hir;
use rustc_middle::hir::map::fn_sig;
use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath;
-use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
use rustc_session::Session;
use rustc_span::def_id::DefId;
+use std::iter;
use GenericArgsInfo::*;
.join(", ")
}
+ fn get_unbound_associated_types(&self) -> Vec<String> {
+ if self.tcx.is_trait(self.def_id) {
+ let items: &AssocItems<'_> = self.tcx.associated_items(self.def_id);
+ items
+ .in_definition_order()
+ .filter(|item| item.kind == AssocKind::Type)
+ .filter(|item| {
+ !self.gen_args.bindings.iter().any(|binding| binding.ident.name == item.name)
+ })
+ .map(|item| item.name.to_ident_string())
+ .collect()
+ } else {
+ Vec::default()
+ }
+ }
+
fn create_error_message(&self) -> String {
let def_path = self.tcx.def_path_str(self.def_id);
let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
fn suggest_removing_args_or_generics(&self, err: &mut Diagnostic) {
let num_provided_lt_args = self.num_provided_lifetime_args();
let num_provided_type_const_args = self.num_provided_type_or_const_args();
+ let unbound_types = self.get_unbound_associated_types();
let num_provided_args = num_provided_lt_args + num_provided_type_const_args;
assert!(num_provided_args > 0);
let redundant_type_or_const_args = num_redundant_type_or_const_args > 0;
let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
+ let provided_args_matches_unbound_traits =
+ unbound_types.len() == num_redundant_type_or_const_args;
let remove_lifetime_args = |err: &mut Diagnostic| {
let mut lt_arg_spans = Vec::new();
);
};
- if remove_entire_generics {
+ // If there is a single unbound associated type and a single excess generic param
+ // suggest replacing the generic param with the associated type bound
+ if provided_args_matches_unbound_traits && !unbound_types.is_empty() {
+ let mut suggestions = vec![];
+ let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..];
+ for (potential, name) in iter::zip(unused_generics, &unbound_types) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(potential.span()) {
+ suggestions.push((potential.span(), format!("{} = {}", name, snippet)));
+ }
+ }
+
+ if !suggestions.is_empty() {
+ err.multipart_suggestion(
+ &format!(
+ "replace the generic bound{s} with the associated type{s}",
+ s = pluralize!(unbound_types.len())
+ ),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ } else if remove_entire_generics {
let span = self
.path_segment
.args
/// be mindful of side effects.
///
/// [`Vec`]: crate::vec::Vec
-#[cfg(not(test))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "vec_macro"]
// required for this macro definition, is not available. Instead use the
// `slice::into_vec` function which is only available with cfg(test)
// NB see the slice::hack module in slice.rs for more information
-#[cfg(test)]
+#[cfg(all(not(no_global_oom_handling), test))]
macro_rules! vec {
() => (
$crate::vec::Vec::new()
//! Compiler intrinsics.
//!
-//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
-//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
+//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
+//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
//!
//! # Const intrinsics
//!
//!
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
-//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
-//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
+//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
+//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get mutated (except inside `UnsafeCell`).
///
/// This applies even if the result of this method is unused!
///
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
- /// In particular, for the duration of this lifetime, the memory the pointer points to must
+ /// In particular, while this reference exists, the memory the pointer points to must
/// not get accessed (read or written) through any other pointer.
///
/// This applies even if the result of this method is unused!
pub(super) fn new(slice: &'a [T], pred: P) -> Self {
Self { v: slice, pred, finished: false }
}
+ /// Returns a slice which contains items not yet handled by split.
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(split_as_slice)]
+ /// let slice = [1,2,3,4,5];
+ /// let mut split = slice.split(|v| v % 2 == 0);
+ /// assert!(split.next().is_some());
+ /// assert_eq!(split.as_slice(), &[3,4,5]);
+ /// ```
+ #[unstable(feature = "split_as_slice", issue = "96137")]
+ pub fn as_slice(&self) -> &'a [T] {
+ if self.finished { &[] } else { &self.v }
+ }
}
#[stable(feature = "core_impl_debug", since = "1.9.0")]
}
}
-macro_rules! u8to64_le {
- ($buf:expr, $i:expr) => {
- $buf[0 + $i] as u64
- | ($buf[1 + $i] as u64) << 8
- | ($buf[2 + $i] as u64) << 16
- | ($buf[3 + $i] as u64) << 24
- | ($buf[4 + $i] as u64) << 32
- | ($buf[5 + $i] as u64) << 40
- | ($buf[6 + $i] as u64) << 48
- | ($buf[7 + $i] as u64) << 56
- };
- ($buf:expr, $i:expr, $len:expr) => {{
- let mut t = 0;
- let mut out = 0;
- while t < $len {
- out |= ($buf[t + $i] as u64) << t * 8;
- t += 1;
- }
- out
- }};
-}
-
fn hash_with<H: Hasher, T: Hash>(mut st: H, x: &T) -> u64 {
x.hash(&mut st);
st.finish()
let mut state_inc = SipHasher13::new_with_keys(k0, k1);
while t < 64 {
- let vec = u8to64_le!(vecs[t], 0);
+ let vec = u64::from_le_bytes(vecs[t]);
let out = hash_with(SipHasher13::new_with_keys(k0, k1), &Bytes(&buf));
assert_eq!(vec, out);
let mut state_inc = SipHasher::new_with_keys(k0, k1);
while t < 64 {
- let vec = u8to64_le!(vecs[t], 0);
+ let vec = u64::from_le_bytes(vecs[t]);
let out = hash_with(SipHasher::new_with_keys(k0, k1), &Bytes(&buf));
assert_eq!(vec, out);
#![feature(sort_internals)]
#![feature(slice_take)]
#![feature(slice_from_ptr_range)]
+#![feature(split_as_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_array_assume_init)]
#![feature(maybe_uninit_write_slice)]
}
}
+#[test]
+fn split_as_slice() {
+ let arr = [1, 2, 3, 4, 5, 6];
+ let mut split = arr.split(|v| v % 2 == 0);
+ assert_eq!(split.as_slice(), &[1, 2, 3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[3, 4, 5, 6]);
+ assert!(split.next().is_some());
+ assert!(split.next().is_some());
+ assert_eq!(split.as_slice(), &[]);
+}
+
#[should_panic]
#[test]
fn slice_split_array_ref_out_of_bounds() {
[dependencies]
std = { path = "../std" }
+# Workaround: when documenting this crate rustdoc will try to load crate named
+# `core` when resolving doc links. Without this line a different `core` will be
+# loaded from sysroot causing duplicate lang items and other similar errors.
+core = { path = "../core" }
/// Run a parser, but fail if the entire input wasn't consumed.
/// Doesn't run atomically.
- fn parse_with<T, F>(&mut self, inner: F) -> Result<T, AddrParseError>
+ fn parse_with<T, F>(&mut self, inner: F, kind: AddrKind) -> Result<T, AddrParseError>
where
F: FnOnce(&mut Parser<'_>) -> Option<T>,
{
let result = inner(self);
- if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(()))
+ if self.state.is_empty() { result } else { None }.ok_or(AddrParseError(kind))
}
/// Peek the next character from the input
impl FromStr for IpAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<IpAddr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_ip_addr())
+ Parser::new(s).parse_with(|p| p.read_ip_addr(), AddrKind::Ip)
}
}
fn from_str(s: &str) -> Result<Ipv4Addr, AddrParseError> {
// don't try to parse if too long
if s.len() > 15 {
- Err(AddrParseError(()))
+ Err(AddrParseError(AddrKind::Ipv4))
} else {
- Parser::new(s).parse_with(|p| p.read_ipv4_addr())
+ Parser::new(s).parse_with(|p| p.read_ipv4_addr(), AddrKind::Ipv4)
}
}
}
impl FromStr for Ipv6Addr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Ipv6Addr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_ipv6_addr())
+ Parser::new(s).parse_with(|p| p.read_ipv6_addr(), AddrKind::Ipv6)
}
}
impl FromStr for SocketAddrV4 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr_v4())
+ Parser::new(s).parse_with(|p| p.read_socket_addr_v4(), AddrKind::SocketV4)
}
}
impl FromStr for SocketAddrV6 {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr_v6())
+ Parser::new(s).parse_with(|p| p.read_socket_addr_v6(), AddrKind::SocketV6)
}
}
impl FromStr for SocketAddr {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<SocketAddr, AddrParseError> {
- Parser::new(s).parse_with(|p| p.read_socket_addr())
+ Parser::new(s).parse_with(|p| p.read_socket_addr(), AddrKind::Socket)
}
}
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum AddrKind {
+ Ip,
+ Ipv4,
+ Ipv6,
+ Socket,
+ SocketV4,
+ SocketV6,
+}
+
/// An error which can be returned when parsing an IP address or a socket address.
///
/// This error is used as the error type for the [`FromStr`] implementation for
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AddrParseError(());
+pub struct AddrParseError(AddrKind);
#[stable(feature = "addr_parse_error_error", since = "1.4.0")]
impl fmt::Display for AddrParseError {
impl Error for AddrParseError {
#[allow(deprecated)]
fn description(&self) -> &str {
- "invalid IP address syntax"
+ match self.0 {
+ AddrKind::Ip => "invalid IP address syntax",
+ AddrKind::Ipv4 => "invalid IPv4 address syntax",
+ AddrKind::Ipv6 => "invalid IPv6 address syntax",
+ AddrKind::Socket => "invalid socket address syntax",
+ AddrKind::SocketV4 => "invalid IPv4 socket address syntax",
+ AddrKind::SocketV6 => "invalid IPv6 socket address syntax",
+ }
}
}
use crate::cell::UnsafeCell;
use crate::collections::VecDeque;
-use crate::ffi::c_void;
use crate::hint;
use crate::ops::{Deref, DerefMut, Drop};
use crate::ptr;
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-pub struct ReentrantMutex {
- inner: *const c_void,
-}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: ptr::null() }
- }
-
- #[inline]
- pub unsafe fn init(&self) {
- let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _);
- }
-
- #[inline]
- pub unsafe fn lock(&self) {
- let _ = abi::recmutex_lock(self.inner);
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- true
- }
-
- #[inline]
- pub unsafe fn unlock(&self) {
- let _ = abi::recmutex_unlock(self.inner);
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- let _ = abi::recmutex_destroy(self.inner);
- }
-}
error::{expect_success, expect_success_aborting, fail, ItronError},
spin::SpinIdOnceCell,
};
-use crate::cell::UnsafeCell;
pub struct Mutex {
/// The ID of the underlying mutex object
unsafe { self.0.unlock() };
}
}
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {
- /// The ID of the underlying mutex object
- mtx: abi::ID,
- /// The lock count.
- count: UnsafeCell<usize>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) }
- }
-
- pub unsafe fn init(&mut self) {
- self.mtx = expect_success(
- unsafe {
- abi::acre_mtx(&abi::T_CMTX {
- // Priority inheritance mutex
- mtxatr: abi::TA_INHERIT,
- // Unused
- ceilpri: 0,
- })
- },
- &"acre_mtx",
- );
- }
-
- pub unsafe fn lock(&self) {
- match unsafe { abi::loc_mtx(self.mtx) } {
- abi::E_OBJ => {
- // Recursive lock
- unsafe {
- let count = &mut *self.count.get();
- if let Some(new_count) = count.checked_add(1) {
- *count = new_count;
- } else {
- // counter overflow
- rtabort!("lock count overflow");
- }
- }
- }
- er => {
- expect_success(er, &"loc_mtx");
- }
- }
- }
-
- pub unsafe fn unlock(&self) {
- unsafe {
- let count = &mut *self.count.get();
- if *count > 0 {
- *count -= 1;
- return;
- }
- }
-
- expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx");
- }
-
- pub unsafe fn try_lock(&self) -> bool {
- let er = unsafe { abi::ploc_mtx(self.mtx) };
- if er == abi::E_OBJ {
- // Recursive lock
- unsafe {
- let count = &mut *self.count.get();
- if let Some(new_count) = count.checked_add(1) {
- *count = new_count;
- } else {
- // counter overflow
- rtabort!("lock count overflow");
- }
- }
- true
- } else if er == abi::E_TMOUT {
- // Locked by another thread
- false
- } else {
- expect_success(er, &"ploc_mtx");
- // Top-level lock by the current thread
- true
- }
- }
-
- pub unsafe fn destroy(&self) {
- expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx");
- }
-}
-use fortanix_sgx_abi::Tcs;
-
-use super::abi::thread;
-
-use super::waitqueue::{try_lock_or_false, NotifiedTcs, SpinMutex, WaitQueue, WaitVariable};
+use super::waitqueue::{try_lock_or_false, SpinMutex, WaitQueue, WaitVariable};
pub struct Mutex {
inner: SpinMutex<WaitVariable<bool>>,
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-struct ReentrantLock {
- owner: Option<Tcs>,
- count: usize,
-}
-
-pub struct ReentrantMutex {
- inner: SpinMutex<WaitVariable<ReentrantLock>>,
-}
-
-impl ReentrantMutex {
- pub const fn uninitialized() -> ReentrantMutex {
- ReentrantMutex {
- inner: SpinMutex::new(WaitVariable::new(ReentrantLock { owner: None, count: 0 })),
- }
- }
-
- #[inline]
- pub unsafe fn init(&self) {}
-
- #[inline]
- pub unsafe fn lock(&self) {
- let mut guard = self.inner.lock();
- match guard.lock_var().owner {
- Some(tcs) if tcs != thread::current() => {
- // Another thread has the lock, wait
- WaitQueue::wait(guard, || {});
- // Another thread has passed the lock to us
- }
- _ => {
- // We are just now obtaining the lock
- guard.lock_var_mut().owner = Some(thread::current());
- guard.lock_var_mut().count += 1;
- }
- }
- }
-
- #[inline]
- pub unsafe fn unlock(&self) {
- let mut guard = self.inner.lock();
- if guard.lock_var().count > 1 {
- guard.lock_var_mut().count -= 1;
- } else {
- match WaitQueue::notify_one(guard) {
- Err(mut guard) => {
- // No other waiters, unlock
- guard.lock_var_mut().count = 0;
- guard.lock_var_mut().owner = None;
- }
- Ok(mut guard) => {
- // There was a thread waiting, just pass the lock
- if let NotifiedTcs::Single(tcs) = guard.notified_tcs() {
- guard.lock_var_mut().owner = Some(tcs)
- } else {
- unreachable!() // called notify_one
- }
- }
- }
- }
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- let mut guard = try_lock_or_false!(self.inner);
- match guard.lock_var().owner {
- Some(tcs) if tcs != thread::current() => {
- // Another thread has the lock
- false
- }
- _ => {
- // We are just now obtaining the lock
- guard.lock_var_mut().owner = Some(thread::current());
- guard.lock_var_mut().count += 1;
- true
- }
- }
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {}
-}
fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> {
// try opening as directory
let fd = match openat_nofollow_dironly(parent_fd, &path) {
- Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => {
+ Err(err) if matches!(err.raw_os_error(), Some(libc::ENOTDIR | libc::ELOOP)) => {
// not a directory - don't traverse further
+ // (for symlinks, older Linux kernels may return ELOOP instead of ENOTDIR)
return match parent_fd {
// unlink...
Some(parent_fd) => {
}
}
-#[cfg(target_os = "emscripten")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
- extern "C" {
- fn emscripten_futex_wait(
- addr: *const AtomicU32,
- val: libc::c_uint,
- max_wait_ms: libc::c_double,
- ) -> libc::c_int;
- }
-
- unsafe {
- emscripten_futex_wait(
- futex,
- expected,
- timeout.map_or(crate::f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
- );
- }
-}
-
/// Wake up one thread that's blocked on futex_wait on this futex.
///
/// Returns true if this actually woke up such a thread,
}
#[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
- extern "C" {
- fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+extern "C" {
+ fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+ fn emscripten_futex_wait(
+ addr: *const AtomicU32,
+ val: libc::c_uint,
+ max_wait_ms: libc::c_double,
+ ) -> libc::c_int;
+}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+ unsafe {
+ emscripten_futex_wait(
+ futex,
+ expected,
+ timeout.map_or(f64::INFINITY, |d| d.as_secs_f64() * 1000.0),
+ ) != -libc::ETIMEDOUT
}
+}
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
unsafe { emscripten_futex_wake(futex, 1) > 0 }
}
+
+#[cfg(target_os = "emscripten")]
+pub fn futex_wake_all(futex: &AtomicU32) {
+ unsafe { emscripten_futex_wake(futex, i32::MAX) };
+}
-use crate::cell::UnsafeCell;
use crate::sync::atomic::{
- AtomicU32, AtomicUsize,
+ AtomicU32,
Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
r
}
}
-
-/// A reentrant mutex. Used by stdout().lock() and friends.
-///
-/// The 'owner' field tracks which thread has locked the mutex.
-///
-/// We use current_thread_unique_ptr() as the thread identifier,
-/// which is just the address of a thread local variable.
-///
-/// If `owner` is set to the identifier of the current thread,
-/// we assume the mutex is already locked and instead of locking it again,
-/// we increment `lock_count`.
-///
-/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
-/// it reaches zero.
-///
-/// `lock_count` is protected by the mutex and only accessed by the thread that has
-/// locked the mutex, so needs no synchronization.
-///
-/// `owner` can be checked by other threads that want to see if they already
-/// hold the lock, so needs to be atomic. If it compares equal, we're on the
-/// same thread that holds the mutex and memory access can use relaxed ordering
-/// since we're not dealing with multiple threads. If it compares unequal,
-/// synchronization is left to the mutex, making relaxed memory ordering for
-/// the `owner` field fine in all cases.
-pub struct ReentrantMutex {
- mutex: Mutex,
- owner: AtomicUsize,
- lock_count: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- #[inline]
- pub const unsafe fn uninitialized() -> Self {
- Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&self) {}
-
- #[inline]
- pub unsafe fn destroy(&self) {}
-
- pub unsafe fn try_lock(&self) -> bool {
- let this_thread = current_thread_unique_ptr();
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- true
- } else if self.mutex.try_lock() {
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- true
- } else {
- false
- }
- }
-
- pub unsafe fn lock(&self) {
- let this_thread = current_thread_unique_ptr();
- if self.owner.load(Relaxed) == this_thread {
- self.increment_lock_count();
- } else {
- self.mutex.lock();
- self.owner.store(this_thread, Relaxed);
- debug_assert_eq!(*self.lock_count.get(), 0);
- *self.lock_count.get() = 1;
- }
- }
-
- unsafe fn increment_lock_count(&self) {
- *self.lock_count.get() = (*self.lock_count.get())
- .checked_add(1)
- .expect("lock count overflow in reentrant mutex");
- }
-
- pub unsafe fn unlock(&self) {
- *self.lock_count.get() -= 1;
- if *self.lock_count.get() == 0 {
- self.owner.store(0, Relaxed);
- self.mutex.unlock();
- }
- }
-}
-
-/// Get an address that is unique per running thread.
-///
-/// This can be used as a non-null usize-sized ID.
-pub fn current_thread_unique_ptr() -> usize {
- // Use a non-drop type to make sure it's still available during thread destruction.
- thread_local! { static X: u8 = const { 0 } }
- X.with(|x| <*const _>::addr(x))
-}
if #[cfg(any(
target_os = "linux",
target_os = "android",
+ all(target_os = "emscripten", target_feature = "atomics"),
))] {
mod futex;
mod futex_rwlock;
- pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex};
+ pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
pub use futex_rwlock::{RwLock, MovableRwLock};
} else {
mod pthread_mutex;
- mod pthread_remutex;
mod pthread_rwlock;
mod pthread_condvar;
pub use pthread_mutex::{Mutex, MovableMutex};
- pub use pthread_remutex::ReentrantMutex;
pub use pthread_rwlock::{RwLock, MovableRwLock};
pub use pthread_condvar::{Condvar, MovableCondvar};
}
+++ /dev/null
-use super::pthread_mutex::PthreadMutexAttr;
-use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
-use crate::sys::cvt_nz;
-
-pub struct ReentrantMutex {
- inner: UnsafeCell<libc::pthread_mutex_t>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
- }
-
- pub unsafe fn init(&self) {
- let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit();
- cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap();
- let attr = PthreadMutexAttr(&mut attr);
- cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE))
- .unwrap();
- cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap();
- }
-
- pub unsafe fn lock(&self) {
- let result = libc::pthread_mutex_lock(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- libc::pthread_mutex_trylock(self.inner.get()) == 0
- }
-
- pub unsafe fn unlock(&self) {
- let result = libc::pthread_mutex_unlock(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-
- pub unsafe fn destroy(&self) {
- let result = libc::pthread_mutex_destroy(self.inner.get());
- debug_assert_eq!(result, 0);
- }
-}
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(target_os = "l4re")]
pub fn current_exe() -> io::Result<PathBuf> {
use crate::io::ErrorKind;
Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
super::unsupported::unsupported()
}
+#[cfg(target_os = "fuchsia")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ use crate::io::ErrorKind;
+
+ #[cfg(test)]
+ use realstd::env;
+
+ #[cfg(not(test))]
+ use crate::env;
+
+ let exe_path = env::args().next().ok_or(io::const_io_error!(
+ ErrorKind::Uncategorized,
+ "an executable path was not found because no arguments were provided through argv"
+ ))?;
+ let path = PathBuf::from(exe_path);
+
+ // Prepend the current working directory to the path if it's not absolute.
+ if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
+}
+
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
use crate::ffi::CStr;
use crate::marker::PhantomData;
use crate::mem;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::ptr;
+use crate::sync::atomic::{self, AtomicPtr, Ordering};
// We can use true weak linkage on ELF targets.
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
}
pub(crate) struct DlsymWeak<F> {
name: &'static str,
- addr: AtomicUsize,
+ func: AtomicPtr<libc::c_void>,
_marker: PhantomData<F>,
}
impl<F> DlsymWeak<F> {
pub(crate) const fn new(name: &'static str) -> Self {
- DlsymWeak { name, addr: AtomicUsize::new(1), _marker: PhantomData }
+ DlsymWeak { name, func: AtomicPtr::new(ptr::invalid_mut(1)), _marker: PhantomData }
}
#[inline]
unsafe {
// Relaxed is fine here because we fence before reading through the
// pointer (see the comment below).
- match self.addr.load(Ordering::Relaxed) {
- 1 => self.initialize(),
- 0 => None,
- addr => {
- let func = mem::transmute_copy::<usize, F>(&addr);
+ match self.func.load(Ordering::Relaxed) {
+ func if func.addr() == 1 => self.initialize(),
+ func if func.is_null() => None,
+ func => {
+ let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
// The caller is presumably going to read through this value
// (by calling the function we've dlsymed). This means we'd
// need to have loaded it with at least C11's consume
// Cold because it should only happen during first-time initialization.
#[cold]
unsafe fn initialize(&self) -> Option<F> {
- assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
+ assert_eq!(mem::size_of::<F>(), mem::size_of::<*mut libc::c_void>());
let val = fetch(self.name);
// This synchronizes with the acquire fence in `get`.
- self.addr.store(val, Ordering::Release);
+ self.func.store(val, Ordering::Release);
- match val {
- 0 => None,
- addr => Some(mem::transmute_copy::<usize, F>(&addr)),
- }
+ if val.is_null() { None } else { Some(mem::transmute_copy::<*mut libc::c_void, F>(&val)) }
}
}
-unsafe fn fetch(name: &str) -> usize {
+unsafe fn fetch(name: &str) -> *mut libc::c_void {
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
Ok(cstr) => cstr,
- Err(..) => return 0,
+ Err(..) => return ptr::null_mut(),
};
- libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
+ libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr())
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
mod mutex;
mod rwlock;
pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
pub use rwlock::{MovableRwLock, RwLock};
#[inline]
pub unsafe fn destroy(&self) {}
}
-
-// All empty stubs because this platform does not yet support threads, so lock
-// acquisition always succeeds.
-pub struct ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex {}
- }
-
- pub unsafe fn init(&self) {}
-
- pub unsafe fn lock(&self) {}
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- true
- }
-
- pub unsafe fn unlock(&self) {}
-
- pub unsafe fn destroy(&self) {}
-}
+++ /dev/null
-use crate::arch::wasm32;
-use crate::cmp;
-use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::locks::Mutex;
-use crate::time::Duration;
-
-pub struct Condvar {
- cnt: AtomicUsize,
-}
-
-pub type MovableCondvar = Condvar;
-
-// Condition variables are implemented with a simple counter internally that is
-// likely to cause spurious wakeups. Blocking on a condition variable will first
-// read the value of the internal counter, unlock the given mutex, and then
-// block if and only if the counter's value is still the same. Notifying a
-// condition variable will modify the counter (add one for now) and then wake up
-// a thread waiting on the address of the counter.
-//
-// A thread waiting on the condition variable will as a result avoid going to
-// sleep if it's notified after the lock is unlocked but before it fully goes to
-// sleep. A sleeping thread is guaranteed to be woken up at some point as it can
-// only be woken up with a call to `wake`.
-//
-// Note that it's possible for 2 or more threads to be woken up by a call to
-// `notify_one` with this implementation. That can happen where the modification
-// of `cnt` causes any threads in the middle of `wait` to avoid going to sleep,
-// and the subsequent `wake` may wake up a thread that's actually blocking. We
-// consider this a spurious wakeup, though, which all users of condition
-// variables must already be prepared to handle. As a result, this source of
-// spurious wakeups is currently though to be ok, although it may be problematic
-// later on if it causes too many spurious wakeups.
-
-impl Condvar {
- pub const fn new() -> Condvar {
- Condvar { cnt: AtomicUsize::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&mut self) {
- // nothing to do
- }
-
- pub unsafe fn notify_one(&self) {
- self.cnt.fetch_add(1, SeqCst);
- // SAFETY: ptr() is always valid
- unsafe {
- wasm32::memory_atomic_notify(self.ptr(), 1);
- }
- }
-
- #[inline]
- pub unsafe fn notify_all(&self) {
- self.cnt.fetch_add(1, SeqCst);
- // SAFETY: ptr() is always valid
- unsafe {
- wasm32::memory_atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone"
- }
- }
-
- pub unsafe fn wait(&self, mutex: &Mutex) {
- // "atomically block and unlock" implemented by loading our current
- // counter's value, unlocking the mutex, and blocking if the counter
- // still has the same value.
- //
- // Notifications happen by incrementing the counter and then waking a
- // thread. Incrementing the counter after we unlock the mutex will
- // prevent us from sleeping and otherwise the call to `wake` will
- // wake us up once we're asleep.
- let ticket = self.cnt.load(SeqCst) as i32;
- mutex.unlock();
- let val = wasm32::memory_atomic_wait32(self.ptr(), ticket, -1);
- // 0 == woken, 1 == not equal to `ticket`, 2 == timeout (shouldn't happen)
- debug_assert!(val == 0 || val == 1);
- mutex.lock();
- }
-
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
- let ticket = self.cnt.load(SeqCst) as i32;
- mutex.unlock();
- let nanos = dur.as_nanos();
- let nanos = cmp::min(i64::MAX as u128, nanos);
-
- // If the return value is 2 then a timeout happened, so we return
- // `false` as we weren't actually notified.
- let ret = wasm32::memory_atomic_wait32(self.ptr(), ticket, nanos as i64) != 2;
- mutex.lock();
- return ret;
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // nothing to do
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
- self.cnt.as_mut_ptr() as *mut i32
- }
-}
use crate::sync::atomic::AtomicU32;
use crate::time::Duration;
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) {
+/// Wait for a futex_wake operation to wake us.
+///
+/// Returns directly if the futex doesn't hold the expected value.
+///
+/// Returns false on timeout, and true in all other cases.
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
unsafe {
wasm32::memory_atomic_wait32(
futex as *const AtomicU32 as *mut i32,
expected as i32,
timeout,
- );
+ ) < 2
}
}
-pub fn futex_wake(futex: &AtomicU32) {
+/// Wake up one thread that's blocked on futex_wait on this futex.
+///
+/// Returns true if this actually woke up such a thread,
+/// or false if no thread was waiting on this futex.
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+ unsafe { wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+}
+
+/// Wake up all threads that are waiting on futex_wait on this futex.
+pub fn futex_wake_all(futex: &AtomicU32) {
unsafe {
- wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1);
+ wasm32::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
}
}
+++ /dev/null
-use crate::arch::wasm32;
-use crate::cell::UnsafeCell;
-use crate::mem;
-use crate::sync::atomic::{AtomicU32, AtomicUsize, Ordering::SeqCst};
-use crate::sys::thread;
-
-pub struct Mutex {
- locked: AtomicUsize,
-}
-
-pub type MovableMutex = Mutex;
-
-// Mutexes have a pretty simple implementation where they contain an `i32`
-// internally that is 0 when unlocked and 1 when the mutex is locked.
-// Acquisition has a fast path where it attempts to cmpxchg the 0 to a 1, and
-// if it fails it then waits for a notification. Releasing a lock is then done
-// by swapping in 0 and then notifying any waiters, if present.
-
-impl Mutex {
- pub const fn new() -> Mutex {
- Mutex { locked: AtomicUsize::new(0) }
- }
-
- #[inline]
- pub unsafe fn init(&mut self) {
- // nothing to do
- }
-
- pub unsafe fn lock(&self) {
- while !self.try_lock() {
- // SAFETY: the caller must uphold the safety contract for `memory_atomic_wait32`.
- let val = unsafe {
- wasm32::memory_atomic_wait32(
- self.ptr(),
- 1, // we expect our mutex is locked
- -1, // wait infinitely
- )
- };
- // we should have either woke up (0) or got a not-equal due to a
- // race (1). We should never time out (2)
- debug_assert!(val == 0 || val == 1);
- }
- }
-
- pub unsafe fn unlock(&self) {
- let prev = self.locked.swap(0, SeqCst);
- debug_assert_eq!(prev, 1);
- wasm32::memory_atomic_notify(self.ptr(), 1); // wake up one waiter, if any
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- // nothing to do
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
- self.locked.as_mut_ptr() as *mut i32
- }
-}
-
-pub struct ReentrantMutex {
- owner: AtomicU32,
- recursions: UnsafeCell<u32>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-// Reentrant mutexes are similarly implemented to mutexes above except that
-// instead of "1" meaning unlocked we use the id of a thread to represent
-// whether it has locked a mutex. That way we have an atomic counter which
-// always holds the id of the thread that currently holds the lock (or 0 if the
-// lock is unlocked).
-//
-// Once a thread acquires a lock recursively, which it detects by looking at
-// the value that's already there, it will update a local `recursions` counter
-// in a nonatomic fashion (as we hold the lock). The lock is then fully
-// released when this recursion counter reaches 0.
-
-impl ReentrantMutex {
- pub const unsafe fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) }
- }
-
- pub unsafe fn init(&self) {
- // nothing to do...
- }
-
- pub unsafe fn lock(&self) {
- let me = thread::my_id();
- while let Err(owner) = self._try_lock(me) {
- // SAFETY: the caller must guarantee that `self.ptr()` and `owner` are valid i32.
- let val = unsafe { wasm32::memory_atomic_wait32(self.ptr(), owner as i32, -1) };
- debug_assert!(val == 0 || val == 1);
- }
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- unsafe { self._try_lock(thread::my_id()).is_ok() }
- }
-
- #[inline]
- unsafe fn _try_lock(&self, id: u32) -> Result<(), u32> {
- let id = id.checked_add(1).unwrap();
- match self.owner.compare_exchange(0, id, SeqCst, SeqCst) {
- // we transitioned from unlocked to locked
- Ok(_) => {
- debug_assert_eq!(*self.recursions.get(), 0);
- Ok(())
- }
-
- // we currently own this lock, so let's update our count and return
- // true.
- Err(n) if n == id => {
- *self.recursions.get() += 1;
- Ok(())
- }
-
- // Someone else owns the lock, let our caller take care of it
- Err(other) => Err(other),
- }
- }
-
- pub unsafe fn unlock(&self) {
- // If we didn't ever recursively lock the lock then we fully unlock the
- // mutex and wake up a waiter, if any. Otherwise we decrement our
- // recursive counter and let some one else take care of the zero.
- match *self.recursions.get() {
- 0 => {
- self.owner.swap(0, SeqCst);
- // SAFETY: the caller must guarantee that `self.ptr()` is valid i32.
- unsafe {
- wasm32::memory_atomic_notify(self.ptr() as *mut i32, 1);
- } // wake up one waiter, if any
- }
- ref mut n => *n -= 1,
- }
- }
-
- pub unsafe fn destroy(&self) {
- // nothing to do...
- }
-
- #[inline]
- fn ptr(&self) -> *mut i32 {
- self.owner.as_mut_ptr() as *mut i32
- }
-}
+++ /dev/null
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{Condvar, Mutex};
-
-pub struct RwLock {
- lock: Mutex,
- cond: Condvar,
- state: UnsafeCell<State>,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
- Unlocked,
- Reading(usize),
- Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
- pub const fn new() -> RwLock {
- RwLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
- }
-
- #[inline]
- pub unsafe fn read(&self) {
- self.lock.lock();
- while !(*self.state.get()).inc_readers() {
- self.cond.wait(&self.lock);
- }
- self.lock.unlock();
- }
-
- #[inline]
- pub unsafe fn try_read(&self) -> bool {
- self.lock.lock();
- let ok = (*self.state.get()).inc_readers();
- self.lock.unlock();
- return ok;
- }
-
- #[inline]
- pub unsafe fn write(&self) {
- self.lock.lock();
- while !(*self.state.get()).inc_writers() {
- self.cond.wait(&self.lock);
- }
- self.lock.unlock();
- }
-
- #[inline]
- pub unsafe fn try_write(&self) -> bool {
- self.lock.lock();
- let ok = (*self.state.get()).inc_writers();
- self.lock.unlock();
- return ok;
- }
-
- #[inline]
- pub unsafe fn read_unlock(&self) {
- self.lock.lock();
- let notify = (*self.state.get()).dec_readers();
- self.lock.unlock();
- if notify {
- // FIXME: should only wake up one of these some of the time
- self.cond.notify_all();
- }
- }
-
- #[inline]
- pub unsafe fn write_unlock(&self) {
- self.lock.lock();
- (*self.state.get()).dec_writers();
- self.lock.unlock();
- // FIXME: should only wake up one of these some of the time
- self.cond.notify_all();
- }
-
- #[inline]
- pub unsafe fn destroy(&self) {
- self.lock.destroy();
- self.cond.destroy();
- }
-}
-
-impl State {
- fn inc_readers(&mut self) -> bool {
- match *self {
- State::Unlocked => {
- *self = State::Reading(1);
- true
- }
- State::Reading(ref mut cnt) => {
- *cnt += 1;
- true
- }
- State::Writing => false,
- }
- }
-
- fn inc_writers(&mut self) -> bool {
- match *self {
- State::Unlocked => {
- *self = State::Writing;
- true
- }
- State::Reading(_) | State::Writing => false,
- }
- }
-
- fn dec_readers(&mut self) -> bool {
- let zero = match *self {
- State::Reading(ref mut cnt) => {
- *cnt -= 1;
- *cnt == 0
- }
- State::Unlocked | State::Writing => invalid(),
- };
- if zero {
- *self = State::Unlocked;
- }
- zero
- }
-
- fn dec_writers(&mut self) {
- match *self {
- State::Writing => {}
- State::Unlocked | State::Reading(_) => invalid(),
- }
- *self = State::Unlocked;
- }
-}
-
-fn invalid() -> ! {
- panic!("inconsistent rwlock");
-}
None
}
}
-
-// We currently just use our own thread-local to store our
-// current thread's ID, and then we lazily initialize it to something allocated
-// from a global counter.
-pub fn my_id() -> u32 {
- use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
-
- static NEXT_ID: AtomicU32 = AtomicU32::new(0);
-
- #[thread_local]
- static mut MY_ID: u32 = 0;
-
- unsafe {
- // If our thread ID isn't set yet then we need to allocate one. Do so
- // with with a simple "atomically add to a global counter" strategy.
- // This strategy doesn't handled what happens when the counter
- // overflows, however, so just abort everything once the counter
- // overflows and eventually we could have some sort of recycling scheme
- // (or maybe this is all totally irrelevant by that point!). In any case
- // though we're using a CAS loop instead of a `fetch_add` to ensure that
- // the global counter never overflows.
- if MY_ID == 0 {
- let mut cur = NEXT_ID.load(SeqCst);
- MY_ID = loop {
- let next = cur.checked_add(1).unwrap_or_else(|| crate::process::abort());
- match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
- Ok(_) => break next,
- Err(i) => cur = i,
- }
- };
- }
- MY_ID
- }
-}
cfg_if::cfg_if! {
if #[cfg(target_feature = "atomics")] {
- #[path = "atomics/condvar.rs"]
- mod condvar;
- #[path = "atomics/mutex.rs"]
- mod mutex;
- #[path = "atomics/rwlock.rs"]
- mod rwlock;
+ #[path = "../unix/locks"]
pub mod locks {
- pub use super::condvar::*;
- pub use super::mutex::*;
- pub use super::rwlock::*;
+ #![allow(unsafe_op_in_unsafe_fn)]
+ mod futex;
+ mod futex_rwlock;
+ pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+ pub use futex_rwlock::{RwLock, MovableRwLock};
}
#[path = "atomics/futex.rs"]
pub mod futex;
pub struct SRWLOCK {
pub ptr: LPVOID,
}
-#[repr(C)]
-pub struct CRITICAL_SECTION {
- CriticalSectionDebug: LPVOID,
- LockCount: LONG,
- RecursionCount: LONG,
- OwningThread: HANDLE,
- LockSemaphore: HANDLE,
- SpinCount: ULONG_PTR,
-}
#[repr(C)]
pub struct REPARSE_MOUNTPOINT_DATA_BUFFER {
#[link(name = "kernel32")]
extern "system" {
pub fn GetCurrentProcessId() -> DWORD;
- pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
- pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
mod mutex;
mod rwlock;
pub use condvar::{Condvar, MovableCondvar};
-pub use mutex::{MovableMutex, Mutex, ReentrantMutex};
+pub use mutex::{MovableMutex, Mutex};
pub use rwlock::{MovableRwLock, RwLock};
//! is that there are no guarantees of fairness.
use crate::cell::UnsafeCell;
-use crate::mem::MaybeUninit;
use crate::sys::c;
pub struct Mutex {
// SRWLock does not need to be destroyed.
}
}
-
-pub struct ReentrantMutex {
- inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
-}
-
-unsafe impl Send for ReentrantMutex {}
-unsafe impl Sync for ReentrantMutex {}
-
-impl ReentrantMutex {
- pub const fn uninitialized() -> ReentrantMutex {
- ReentrantMutex { inner: MaybeUninit::uninit() }
- }
-
- pub unsafe fn init(&self) {
- c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- pub unsafe fn lock(&self) {
- c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> bool {
- c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0
- }
-
- pub unsafe fn unlock(&self) {
- c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-
- pub unsafe fn destroy(&self) {
- c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
- }
-}
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
+use crate::cell::UnsafeCell;
use crate::marker::PhantomPinned;
use crate::ops::Deref;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::pin::Pin;
+use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::sys::locks as sys;
/// A re-entrant mutual exclusion
/// This mutex will block *other* threads waiting for the lock to become
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
+///
+/// This is used by stdout().lock() and friends.
+///
+/// ## Implementation details
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
pub struct ReentrantMutex<T> {
- inner: sys::ReentrantMutex,
+ mutex: sys::Mutex,
+ owner: AtomicUsize,
+ lock_count: UnsafeCell<u32>,
data: T,
_pinned: PhantomPinned,
}
/// lock/unlock methods safe.
pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
ReentrantMutex {
- inner: sys::ReentrantMutex::uninitialized(),
+ mutex: sys::Mutex::new(),
+ owner: AtomicUsize::new(0),
+ lock_count: UnsafeCell::new(0),
data: t,
_pinned: PhantomPinned,
}
/// Unsafe to call more than once, and must be called after this will no
/// longer move in memory.
pub unsafe fn init(self: Pin<&mut Self>) {
- self.get_unchecked_mut().inner.init()
+ self.get_unchecked_mut().mutex.init()
}
/// Acquires a mutex, blocking the current thread until it is able to do so.
/// this call will return failure if the mutex would otherwise be
/// acquired.
pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
- unsafe { self.inner.lock() }
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock,
+ // and since self is pinned we can safely call the lock() on the mutex.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ } else {
+ self.mutex.lock();
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ }
+ }
ReentrantMutexGuard { lock: self }
}
/// this call will return failure if the mutex would otherwise be
/// acquired.
pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> {
- if unsafe { self.inner.try_lock() } {
- Some(ReentrantMutexGuard { lock: self })
- } else {
- None
+ let this_thread = current_thread_unique_ptr();
+ // Safety: We only touch lock_count when we own the lock,
+ // and since self is pinned we can safely call the try_lock on the mutex.
+ unsafe {
+ if self.owner.load(Relaxed) == this_thread {
+ self.increment_lock_count();
+ Some(ReentrantMutexGuard { lock: self })
+ } else if self.mutex.try_lock() {
+ self.owner.store(this_thread, Relaxed);
+ debug_assert_eq!(*self.lock_count.get(), 0);
+ *self.lock_count.get() = 1;
+ Some(ReentrantMutexGuard { lock: self })
+ } else {
+ None
+ }
}
}
+
+ unsafe fn increment_lock_count(&self) {
+ *self.lock_count.get() = (*self.lock_count.get())
+ .checked_add(1)
+ .expect("lock count overflow in reentrant mutex");
+ }
}
impl<T> Drop for ReentrantMutex<T> {
fn drop(&mut self) {
- // This is actually safe b/c we know that there is no further usage of
- // this mutex (it's up to the user to arrange for a mutex to get
- // dropped, that's not our job)
- unsafe { self.inner.destroy() }
+ // Safety: We're the unique owner of this mutex and not going to use it afterwards.
+ unsafe { self.mutex.destroy() }
}
}
impl<T> Drop for ReentrantMutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
+ // Safety: We own the lock, and the lock is pinned.
unsafe {
- self.lock.inner.unlock();
+ *self.lock.lock_count.get() -= 1;
+ if *self.lock.lock_count.get() == 0 {
+ self.lock.owner.store(0, Relaxed);
+ self.lock.mutex.unlock();
+ }
}
}
}
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+ // Use a non-drop type to make sure it's still available during thread destruction.
+ thread_local! { static X: u8 = const { 0 } }
+ X.with(|x| <*const _>::addr(x))
+}
return os.path.join(self.bin_root(True), '.rustfmt-stamp')
def llvm_stamp(self):
- """Return the path for .rustfmt-stamp
+ """Return the path for .llvm-stamp
>>> rb = RustBuild()
>>> rb.build_dir = "build"
self
}
+ // single alias, which does not correspond to any on-disk path
+ pub fn alias(mut self, alias: &str) -> Self {
+ assert!(
+ !self.builder.src.join(alias).exists(),
+ "use `builder.path()` for real paths: {}",
+ alias
+ );
+ self.paths.insert(PathSet::Set(
+ std::iter::once(TaskPath { path: alias.into(), kind: Some(self.kind) }).collect(),
+ ));
+ self
+ }
+
// single, non-aliased path
pub fn path(self, path: &str) -> Self {
self.paths(&[path])
// multiple aliases for the same job
pub fn paths(mut self, paths: &[&str]) -> Self {
self.paths.insert(PathSet::Set(
- paths.iter().map(|p| TaskPath { path: p.into(), kind: Some(self.kind) }).collect(),
+ paths
+ .iter()
+ .map(|p| {
+ // FIXME(#96188): make sure this is actually a path.
+ // This currently breaks for paths within submodules.
+ //assert!(
+ // self.builder.src.join(p).exists(),
+ // "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
+ // p
+ //);
+ TaskPath { path: p.into(), kind: Some(self.kind) }
+ })
+ .collect(),
));
self
}
build.verbose(&format!("AR_{} = {:?}", &target.triple, ar));
build.ar.insert(target, ar);
}
+
+ if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
+ build.ranlib.insert(target, ranlib);
+ }
}
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = run.builder.config.docs;
- run.path("rust-docs").default_condition(default)
+ run.alias("rust-docs").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("rustc-docs").default_condition(builder.config.compiler_docs)
+ run.alias("rustc-docs").default_condition(builder.config.compiler_docs)
}
fn make_run(run: RunConfig<'_>) {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-mingw")
+ run.alias("rust-mingw")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rustc")
+ run.alias("rustc")
}
fn make_run(run: RunConfig<'_>) {
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/lldb_batchmode.py")
+ run.path("src/etc/lldb_batchmode.py")
}
fn make_run(run: RunConfig<'_>) {
const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-std")
+ run.alias("rust-std")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rustc-dev")
+ run.alias("rustc-dev")
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "analysis");
- run.path("rust-analysis").default_condition(default)
+ run.alias("rust-analysis").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-src")
+ run.alias("rust-src")
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("rustc-src").default_condition(builder.config.rust_dist_src)
+ run.alias("rustc-src").default_condition(builder.config.rust_dist_src)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "cargo");
- run.path("cargo").default_condition(default)
+ run.alias("cargo").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rls");
- run.path("rls").default_condition(default)
+ run.alias("rls").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rust-analyzer");
- run.path("rust-analyzer").default_condition(default)
+ run.alias("rust-analyzer").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "clippy");
- run.path("clippy").default_condition(default)
+ run.alias("clippy").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "miri");
- run.path("miri").default_condition(default)
+ run.alias("miri").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "rustfmt");
- run.path("rustfmt").default_condition(default)
+ run.alias("rustfmt").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
// we run the step by default when only `extended = true`, and decide whether to actually
// run it or not later.
let default = run.builder.config.extended;
- run.path("rust-demangler").default_condition(default)
+ run.alias("rust-demangler").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let builder = run.builder;
- run.path("extended").default_condition(builder.config.extended)
+ run.alias("extended").default_condition(builder.config.extended)
}
fn make_run(run: RunConfig<'_>) {
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let default = should_build_extended_tool(&run.builder, "llvm-tools");
- run.path("llvm-tools").default_condition(default)
+ // FIXME: allow using the names of the tools themselves?
+ run.alias("llvm-tools").default_condition(default)
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("rust-dev")
+ run.alias("rust-dev")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("build-manifest")
+ run.alias("build-manifest")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("reproducible-artifacts")
+ run.alias("reproducible-artifacts")
}
fn make_run(run: RunConfig<'_>) {
macro_rules! install {
(($sel:ident, $builder:ident, $_config:ident),
$($name:ident,
- $path:expr,
+ $condition_name: ident = $path_or_alias: literal,
$default_cond:expr,
only_hosts: $only_hosts:expr,
$run_item:block $(, $c:ident)*;)+) => {
#[allow(dead_code)]
fn should_build(config: &Config) -> bool {
config.extended && config.tools.as_ref()
- .map_or(true, |t| t.contains($path))
+ .map_or(true, |t| t.contains($path_or_alias))
}
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
let $_config = &run.builder.config;
- run.path($path).default_condition($default_cond)
+ run.$condition_name($path_or_alias).default_condition($default_cond)
}
fn make_run(run: RunConfig<'_>) {
}
install!((self, builder, _config),
- Docs, "src/doc", _config.docs, only_hosts: false, {
+ Docs, path = "src/doc", _config.docs, only_hosts: false, {
let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs");
install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball);
};
- Std, "library/std", true, only_hosts: false, {
+ Std, path = "library/std", true, only_hosts: false, {
for target in &builder.targets {
// `expect` should be safe, only None when host != build, but this
// only runs when host == build
install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball);
}
};
- Cargo, "cargo", Self::should_build(_config), only_hosts: true, {
+ Cargo, alias = "cargo", Self::should_build(_config), only_hosts: true, {
let tarball = builder
.ensure(dist::Cargo { compiler: self.compiler, target: self.target })
.expect("missing cargo");
install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball);
};
- Rls, "rls", Self::should_build(_config), only_hosts: true, {
+ Rls, alias = "rls", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) {
install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball);
} else {
);
}
};
- RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, {
+ RustAnalyzer, alias = "rust-analyzer", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) =
builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target })
{
);
}
};
- Clippy, "clippy", Self::should_build(_config), only_hosts: true, {
+ Clippy, alias = "clippy", Self::should_build(_config), only_hosts: true, {
let tarball = builder
.ensure(dist::Clippy { compiler: self.compiler, target: self.target })
.expect("missing clippy");
install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball);
};
- Miri, "miri", Self::should_build(_config), only_hosts: true, {
+ Miri, alias = "miri", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) {
install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball);
} else {
);
}
};
- Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, {
+ Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Rustfmt {
compiler: self.compiler,
target: self.target
);
}
};
- RustDemangler, "rust-demangler", Self::should_build(_config), only_hosts: true, {
+ RustDemangler, alias = "rust-demangler", Self::should_build(_config), only_hosts: true, {
// Note: Even though `should_build` may return true for `extended` default tools,
// dist::RustDemangler may still return None, unless the target-dependent `profiler` config
// is also true, or the `tools` array explicitly includes "rust-demangler".
);
}
};
- Analysis, "analysis", Self::should_build(_config), only_hosts: false, {
+ Analysis, alias = "analysis", Self::should_build(_config), only_hosts: false, {
// `expect` should be safe, only None with host != build, but this
// only uses the `build` compiler
let tarball = builder.ensure(dist::Analysis {
}).expect("missing analysis");
install_sh(builder, "analysis", self.compiler.stage, Some(self.target), &tarball);
};
- Rustc, "src/librustc", true, only_hosts: true, {
+ Rustc, path = "compiler/rustc", true, only_hosts: true, {
let tarball = builder.ensure(dist::Rustc {
compiler: builder.compiler(builder.top_stage, self.target),
});
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project").path("src/llvm-project/llvm").path("src/llvm")
+ run.path("src/llvm-project").path("src/llvm-project/llvm")
}
fn make_run(run: RunConfig<'_>) {
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project/lld").path("src/tools/lld")
+ run.path("src/llvm-project/lld")
}
fn make_run(run: RunConfig<'_>) {
type Output = Vec<SanitizerRuntime>;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("src/llvm-project/compiler-rt").path("src/sanitizers")
+ run.alias("sanitizers")
}
fn make_run(run: RunConfig<'_>) {
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
- let compiler = builder.compiler(builder.top_stage, run.build_triple());
+ let host = run.build_triple();
+ let compiler = builder.compiler_for(builder.top_stage, host, host);
let krate = builder.crate_paths[&run.path];
let test_kind = builder.kind.into();
fn make_run(run: RunConfig<'_>) {
let builder = run.builder;
- let compiler = builder.compiler(builder.top_stage, run.build_triple());
+ let host = run.build_triple();
+ let compiler = builder.compiler_for(builder.top_stage, host, host);
let test_kind = builder.kind.into();
let krate = builder.crate_paths[&run.path];
type Output = ();
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("distcheck")
+ run.alias("distcheck")
}
fn make_run(run: RunConfig<'_>) {
}
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- run.path("check-tools")
+ run.alias("check-tools")
}
fn make_run(run: RunConfig<'_>) {
-Subproject commit ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8
+Subproject commit 765318b844569a642ceef7bf1adab9639cbf6af3
-Subproject commit 11f1165e8a2f5840467e748c8108dc53c948ee9a
+Subproject commit c7d8467ca9158da58ef295ae65dbf00a308752d9
-Subproject commit c97d14fa6fed0baa9255432b8a93cb70614f80e3
+Subproject commit b5f6c2362baf932db9440fbfcb509b309237ee85
-Subproject commit ec954f35eedf592cd173b21c05a7f80a65b61d8a
+Subproject commit c2a98d9fc5d29c481d42052fbeccfde15ed03116
-Subproject commit 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad
+Subproject commit eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c
+++ /dev/null
-# `extern-location`
-
-MCP for this feature: [#303]
-
-[#303]: https://github.com/rust-lang/compiler-team/issues/303
-
-------------------------
-
-The `unused-extern-crates` lint reports when a crate was specified on the rustc
-command-line with `--extern name=path` but no symbols were referenced in it.
-This is useful to know, but it's hard to map that back to a specific place a user
-or tool could fix (ie, to remove the unused dependency).
-
-The `--extern-location` flag allows the build system to associate a location with
-the `--extern` option, which is then emitted as part of the diagnostics. This location
-is abstract and just round-tripped through rustc; the compiler never attempts to
-interpret it in any way.
-
-There are two supported forms of location: a bare string, or a blob of json:
-- `--extern-location foo=raw:Makefile:123` would associate the raw string `Makefile:123`
-- `--extern-location 'bar=json:{"target":"//my_project:library","dep":"//common:serde"}` would
- associate the json structure with `--extern bar=<path>`, indicating which dependency of
- which rule introduced the unused extern crate.
-
-This primarily intended to be used with tooling - for example a linter which can automatically
-remove unused dependencies - rather than being directly presented to users.
-
-`raw` locations are presented as part of the normal rendered diagnostics and included in
-the json form. `json` locations are only included in the json form of diagnostics,
-as a `tool_metadata` field. For `raw` locations `tool_metadata` is simply a json string,
-whereas `json` allows the rustc invoker to fully control its form and content.
else:
actual_str = flatten(actual_tree)
+ # Conditions:
+ # 1. Is --bless
+ # 2. Are actual and expected tree different
+ # 3. Are actual and expected text different
if not expected_str \
- or (not normalize_to_text and
+ or (not normalize_to_text and \
not compare_tree(make_xml(actual_str), make_xml(expected_str), stderr)) \
or (normalize_to_text and actual_str != expected_str):
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
// this is the ID of the `extern crate` statement
let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
// this is the ID of the crate itself
- let crate_def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let crate_def_id = cnum.as_def_id();
let attrs = cx.tcx.hir().attrs(krate.hir_id());
let ty_vis = cx.tcx.visibility(krate.def_id);
let please_inline = ty_vis.is_public()
} else {
if inline_attr.is_none() {
if let Res::Def(DefKind::Mod, did) = path.res {
- if !did.is_local() && did.index == CRATE_DEF_INDEX {
+ if !did.is_local() && did.is_crate_root() {
// if we're `pub use`ing an extern crate root, don't inline it unless we
// were specifically asked for it
denied = true;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyId, Mutability};
use rustc_index::vec::IndexVec;
ItemId::Primitive(_, krate) => krate,
}
}
-
- #[inline]
- crate fn index(self) -> Option<DefIndex> {
- match self {
- ItemId::DefId(id) => Some(id.index),
- _ => None,
- }
- }
}
impl From<DefId> for ItemId {
#[inline]
crate fn def_id(&self) -> DefId {
- DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
+ self.crate_num.as_def_id()
}
crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
// Failing that, see if there's an attribute specifying where to find this
// external crate
- let did = DefId { krate: self.crate_num, index: CRATE_DEF_INDEX };
+ let did = self.crate_num.as_def_id();
tcx.get_attrs(did)
.lists(sym::doc)
.filter(|a| a.has_name(sym::html_root_url))
}
crate fn is_crate(&self) -> bool {
- self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.index == CRATE_DEF_INDEX)
+ self.is_mod() && self.item_id.as_def_id().map_or(false, |did| did.is_crate_root())
}
crate fn is_mod(&self) -> bool {
self.type_() == ItemType::Module
attrs: &[ast::Attribute],
additional_attrs: Option<(&[ast::Attribute], DefId)>,
) -> Attributes {
- let mut doc_strings: Vec<DocFragment> = vec![];
- let clean_attr = |(attr, parent_module): (&ast::Attribute, Option<DefId>)| {
- if let Some((value, kind)) = attr.doc_str_and_comment_kind() {
- trace!("got doc_str={:?}", value);
- let value = beautify_doc_string(value, kind);
+ // Additional documentation should be shown before the original documentation.
+ let attrs1 = additional_attrs
+ .into_iter()
+ .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+ let attrs2 = attrs.iter().map(|attr| (attr, None));
+ Attributes::from_ast_iter(attrs1.chain(attrs2), false)
+ }
+
+ crate fn from_ast_iter<'a>(
+ attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>,
+ doc_only: bool,
+ ) -> Attributes {
+ let mut doc_strings = Vec::new();
+ let mut other_attrs = Vec::new();
+ for (attr, parent_module) in attrs {
+ if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
+ trace!("got doc_str={doc_str:?}");
+ let doc = beautify_doc_string(doc_str, comment_kind);
let kind = if attr.is_doc_comment() {
DocFragmentKind::SugaredDoc
} else {
DocFragmentKind::RawDoc
};
-
- let frag =
- DocFragment { span: attr.span, doc: value, kind, parent_module, indent: 0 };
-
- doc_strings.push(frag);
-
- None
- } else {
- Some(attr.clone())
+ let fragment = DocFragment { span: attr.span, doc, kind, parent_module, indent: 0 };
+ doc_strings.push(fragment);
+ } else if !doc_only {
+ other_attrs.push(attr.clone());
}
- };
-
- // Additional documentation should be shown before the original documentation
- let other_attrs = additional_attrs
- .into_iter()
- .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
- .chain(attrs.iter().map(|attr| (attr, None)))
- .filter_map(clean_attr)
- .collect();
+ }
Attributes { doc_strings, other_attrs }
}
}
/// Return the doc-comments on this item, grouped by the module they came from.
- ///
/// The module can be different if this is a re-export with added documentation.
- crate fn collapsed_doc_value_by_module_level(&self) -> FxHashMap<Option<DefId>, String> {
- let mut ret = FxHashMap::default();
- if self.doc_strings.len() == 0 {
- return ret;
- }
- let last_index = self.doc_strings.len() - 1;
-
- for (i, new_frag) in self.doc_strings.iter().enumerate() {
- let out = ret.entry(new_frag.parent_module).or_default();
- add_doc_fragment(out, new_frag);
- if i == last_index {
- out.pop();
- }
+ ///
+ /// The last newline is not trimmed so the produced strings are reusable between
+ /// early and late doc link resolution regardless of their position.
+ crate fn prepare_to_doc_link_resolution(&self) -> FxHashMap<Option<DefId>, String> {
+ let mut res = FxHashMap::default();
+ for fragment in &self.doc_strings {
+ let out_str = res.entry(fragment.parent_module).or_default();
+ add_doc_fragment(out_str, fragment);
}
- ret
+ res
}
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
-use rustc_hir::def::Res;
+use rustc_hir::def::{Namespace, Res};
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{HirId, Path, TraitCandidate};
use crate::clean::{self, ItemId, TraitWithExtraInfo};
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
use crate::formats::cache::Cache;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
use crate::passes::{self, Condition::*};
crate use rustc_session::config::{DebuggingOptions, Input, Options};
crate struct ResolverCaches {
+ crate markdown_links: Option<FxHashMap<String, Vec<PreprocessedMarkdownLink>>>,
+ crate doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<NodeId>>>,
/// Traits in scope for a given module.
/// See `collect_intra_doc_links::traits_implemented_by` for more details.
crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
use std::mem;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::TyCtxt;
use rustc_span::{sym, Symbol};
// A crate has a module at its root, containing all items,
// which should not be indexed. The crate-item itself is
// inserted later on when serializing the search-index.
- if item.item_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
+ if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) {
let desc = item.doc_value().map_or_else(String::new, |x| {
short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
use rustc_middle::ty;
use rustc_middle::ty::DefIdTree;
use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::{sym, Symbol};
use rustc_target::spec::abi::Abi;
clause = clause.replace("<br>", &format!("<br>{}", padding));
clause.insert_str(0, &" ".repeat(indent.saturating_sub(1)));
if !end_newline {
- clause.insert_str(0, "<br>");
+ // we insert the <br> after a single space but before multiple spaces at the start
+ clause.insert_str(if indent == 0 { 1 } else { 0 }, "<br>");
}
}
write!(f, "{}", clause)
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
- if vis_did.index == CRATE_DEF_INDEX {
+ if vis_did.is_crate_root() {
"pub(crate) ".to_owned()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(tcx, item_did);
- if vis_did.index == CRATE_DEF_INDEX {
+ if vis_did.is_crate_root() {
"pub(crate) ".to_owned()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
pub range: Range<usize>,
}
-crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
+crate fn markdown_links<R>(md: &str, filter_map: impl Fn(MarkdownLink) -> Option<R>) -> Vec<R> {
if md.is_empty() {
return vec![];
}
let mut push = |link: BrokenLink<'_>| {
let span = span_for_link(&link.reference, link.span);
- links.borrow_mut().push(MarkdownLink {
+ filter_map(MarkdownLink {
kind: LinkType::ShortcutUnknown,
link: link.reference.to_string(),
range: span,
- });
+ })
+ .map(|link| links.borrow_mut().push(link));
None
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut push))
let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
for ev in iter {
- if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
+ if let Event::Start(Tag::Link(
+ // `<>` links cannot be intra-doc links so we skip them.
+ kind @ (LinkType::Inline
+ | LinkType::Reference
+ | LinkType::ReferenceUnknown
+ | LinkType::Collapsed
+ | LinkType::CollapsedUnknown
+ | LinkType::Shortcut
+ | LinkType::ShortcutUnknown),
+ dest,
+ _,
+ )) = ev.0
+ {
debug!("found link: {dest}");
let span = span_for_link(&dest, ev.1);
- links.borrow_mut().push(MarkdownLink { kind, link: dest.into_string(), range: span });
+ filter_map(MarkdownLink { kind, link: dest.into_string(), range: span })
+ .map(|link| links.borrow_mut().push(link));
}
}
/**
* @typedef {{
- * raw: string,
- * query: string,
- * type: string,
- * id: string,
+ * name: string,
+ * fullPath: Array<string>,
+ * pathWithoutLast: Array<string>,
+ * pathLast: string,
+ * generics: Array<QueryElement>,
+ * }}
+ */
+var QueryElement;
+
+/**
+ * @typedef {{
+ * pos: number,
+ * totalElems: number,
+ * typeFilter: (null|string),
+ * userQuery: string,
+ * }}
+ */
+var ParserState;
+
+/**
+ * @typedef {{
+ * original: string,
+ * userQuery: string,
+ * typeFilter: number,
+ * elems: Array<QueryElement>,
+ * args: Array<QueryElement>,
+ * returned: Array<QueryElement>,
+ * foundElems: number,
* }}
*/
var ParsedQuery;
* }}
*/
var Row;
+
+/**
+ * @typedef {{
+ * in_args: Array<Object>,
+ * returned: Array<Object>,
+ * others: Array<Object>,
+ * query: ParsedQuery,
+ * }}
+ */
+var ResultsTable;
+
+/**
+ * @typedef {{
+ * desc: string,
+ * displayPath: string,
+ * fullPath: string,
+ * href: string,
+ * id: number,
+ * lev: number,
+ * name: string,
+ * normalizedName: string,
+ * parent: (Object|undefined),
+ * path: string,
+ * ty: number,
+ * }}
+ */
+var Results;
});
}
-function removeEmptyStringsFromArray(x) {
- for (var i = 0, len = x.length; i < len; ++i) {
- if (x[i] === "") {
- x.splice(i, 1);
- i -= 1;
- }
- }
-}
-
/**
* A function to compute the Levenshtein distance between two strings
* Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
searchState.input.value = params.search || "";
}
+ function isWhitespace(c) {
+ return " \t\n\r".indexOf(c) !== -1;
+ }
+
+ function isSpecialStartCharacter(c) {
+ return "<\"".indexOf(c) !== -1;
+ }
+
+ function isEndCharacter(c) {
+ return ",>-".indexOf(c) !== -1;
+ }
+
+ function isStopCharacter(c) {
+ return isWhitespace(c) || isEndCharacter(c);
+ }
+
+ function isErrorCharacter(c) {
+ return "()".indexOf(c) !== -1;
+ }
+
+ function itemTypeFromName(typename) {
+ for (var i = 0, len = itemTypes.length; i < len; ++i) {
+ if (itemTypes[i] === typename) {
+ return i;
+ }
+ }
+
+ throw new Error("Unknown type filter `" + typename + "`");
+ }
+
+ /**
+ * If we encounter a `"`, then we try to extract the string from it until we find another `"`.
+ *
+ * This function will throw an error in the following cases:
+ * * There is already another string element.
+ * * We are parsing a generic argument.
+ * * There is more than one element.
+ * * There is no closing `"`.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {boolean} isInGenerics
+ */
+ function getStringElem(query, parserState, isInGenerics) {
+ if (isInGenerics) {
+ throw new Error("`\"` cannot be used in generics");
+ } else if (query.literalSearch) {
+ throw new Error("Cannot have more than one literal search element");
+ } else if (parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("Cannot use literal search when there is more than one element");
+ }
+ parserState.pos += 1;
+ var start = parserState.pos;
+ var end = getIdentEndPosition(parserState);
+ if (parserState.pos >= parserState.length) {
+ throw new Error("Unclosed `\"`");
+ } else if (parserState.userQuery[end] !== "\"") {
+ throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
+ } else if (start === end) {
+ throw new Error("Cannot have empty string element");
+ }
+ // To skip the quote at the end.
+ parserState.pos += 1;
+ query.literalSearch = true;
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "::".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isPathStart(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
+ }
+
+ /**
+ * Returns `true` if the current parser position is starting with "->".
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {boolean}
+ */
+ function isReturnArrow(parserState) {
+ return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
+ }
+
+ /**
+ * Returns `true` if the given `c` character is valid for an ident.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isIdentCharacter(c) {
+ return (
+ c === '_' ||
+ (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z'));
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a separator.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isSeparatorCharacter(c) {
+ return c === "," || isWhitespaceCharacter(c);
+ }
+
+ /**
+ * Returns `true` if the given `c` character is a whitespace.
+ *
+ * @param {string} c
+ *
+ * @return {boolean}
+ */
+ function isWhitespaceCharacter(c) {
+ return c === " " || c === "\t";
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {string} name - Name of the query element.
+ * @param {Array<QueryElement>} generics - List of generics of this query element.
+ *
+ * @return {QueryElement} - The newly created `QueryElement`.
+ */
+ function createQueryElement(query, parserState, name, generics, isInGenerics) {
+ if (name === '*' || (name.length === 0 && generics.length === 0)) {
+ return;
+ }
+ if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
+ throw new Error("You cannot have more than one element if you use quotes");
+ }
+ var pathSegments = name.split("::");
+ if (pathSegments.length > 1) {
+ for (var i = 0, len = pathSegments.length; i < len; ++i) {
+ var pathSegment = pathSegments[i];
+
+ if (pathSegment.length === 0) {
+ if (i === 0) {
+ throw new Error("Paths cannot start with `::`");
+ } else if (i + 1 === len) {
+ throw new Error("Paths cannot end with `::`");
+ }
+ throw new Error("Unexpected `::::`");
+ }
+ }
+ }
+ // In case we only have something like `<p>`, there is no name.
+ if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.totalElems += 1;
+ if (isInGenerics) {
+ parserState.genericsElems += 1;
+ }
+ return {
+ name: name,
+ fullPath: pathSegments,
+ pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
+ pathLast: pathSegments[pathSegments.length - 1],
+ generics: generics,
+ };
+ }
+
+ /**
+ * This function goes through all characters until it reaches an invalid ident character or the
+ * end of the query. It returns the position of the last character of the ident.
+ *
+ * @param {ParserState} parserState
+ *
+ * @return {integer}
+ */
+ function getIdentEndPosition(parserState) {
+ var end = parserState.pos;
+ while (parserState.pos < parserState.length) {
+ var c = parserState.userQuery[parserState.pos];
+ if (!isIdentCharacter(c)) {
+ if (isErrorCharacter(c)) {
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (
+ isStopCharacter(c) ||
+ isSpecialStartCharacter(c) ||
+ isSeparatorCharacter(c))
+ {
+ break;
+ }
+ // If we allow paths ("str::string" for example).
+ else if (c === ":") {
+ if (!isPathStart(parserState)) {
+ break;
+ }
+ // Skip current ":".
+ parserState.pos += 1;
+ } else {
+ throw new Error(`Unexpected \`${c}\``);
+ }
+ }
+ parserState.pos += 1;
+ end = parserState.pos;
+ }
+ return end;
+ }
+
+ /**
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {boolean} isInGenerics
+ */
+ function getNextElem(query, parserState, elems, isInGenerics) {
+ var generics = [];
+
+ var start = parserState.pos;
+ var end;
+ // We handle the strings on their own mostly to make code easier to follow.
+ if (parserState.userQuery[parserState.pos] === "\"") {
+ start += 1;
+ getStringElem(query, parserState, isInGenerics);
+ end = parserState.pos - 1;
+ } else {
+ end = getIdentEndPosition(parserState);
+ }
+ if (parserState.pos < parserState.length &&
+ parserState.userQuery[parserState.pos] === "<")
+ {
+ if (isInGenerics) {
+ throw new Error("Unexpected `<` after `<`");
+ } else if (start >= end) {
+ throw new Error("Found generics without a path");
+ }
+ parserState.pos += 1;
+ getItemsBefore(query, parserState, generics, ">");
+ }
+ if (start >= end && generics.length === 0) {
+ return;
+ }
+ elems.push(
+ createQueryElement(
+ query,
+ parserState,
+ parserState.userQuery.slice(start, end),
+ generics,
+ isInGenerics
+ )
+ );
+ }
+
+ /**
+ * This function parses the next query element until it finds `endChar`, calling `getNextElem`
+ * to collect each element.
+ *
+ * If there is no `endChar`, this function will implicitly stop at the end without raising an
+ * error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {string} endChar - This function will stop when it'll encounter this
+ * character.
+ */
+ function getItemsBefore(query, parserState, elems, endChar) {
+ var foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ var c = parserState.userQuery[parserState.pos];
+ if (c === endChar) {
+ break;
+ } else if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ foundStopChar = true;
+ continue;
+ } else if (c === ":" && isPathStart(parserState)) {
+ throw new Error("Unexpected `::`: paths cannot start with `::`");
+ } else if (c === ":" || isEndCharacter(c)) {
+ var extra = "";
+ if (endChar === ">") {
+ extra = "`<`";
+ } else if (endChar === "") {
+ extra = "`->`";
+ }
+ throw new Error("Unexpected `" + c + "` after " + extra);
+ }
+ if (!foundStopChar) {
+ if (endChar !== "") {
+ throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
+ }
+ var posBefore = parserState.pos;
+ getNextElem(query, parserState, elems, endChar === ">");
+ // This case can be encountered if `getNextElem` encounted a "stop character" right from
+ // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
+ // current position to continue the parsing.
+ if (posBefore === parserState.pos) {
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ // We are either at the end of the string or on the `endChar`` character, let's move forward
+ // in any case.
+ parserState.pos += 1;
+ }
+
+ /**
+ * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
+ * if empty).
+ *
+ * @param {ParserState} parserState
+ */
+ function checkExtraTypeFilterCharacters(parserState) {
+ var query = parserState.userQuery;
+
+ for (var pos = 0; pos < parserState.pos; ++pos) {
+ if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
+ throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
+ }
+ }
+ }
+
+ /**
+ * Parses the provided `query` input to fill `parserState`. If it encounters an error while
+ * parsing `query`, it'll throw an error.
+ *
+ * @param {ParsedQuery} query
+ * @param {ParserState} parserState
+ */
+ function parseInput(query, parserState) {
+ var c, before;
+ var foundStopChar = true;
+
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isStopCharacter(c)) {
+ foundStopChar = true;
+ if (isSeparatorCharacter(c)) {
+ parserState.pos += 1;
+ continue;
+ } else if (c === "-" || c === ">") {
+ if (isReturnArrow(parserState)) {
+ break;
+ }
+ throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
+ }
+ throw new Error(`Unexpected \`${c}\``);
+ } else if (c === ":" && !isPathStart(parserState)) {
+ if (parserState.typeFilter !== null) {
+ throw new Error("Unexpected `:`");
+ }
+ if (query.elems.length === 0) {
+ throw new Error("Expected type filter before `:`");
+ } else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
+ throw new Error("Unexpected `:`");
+ } else if (query.literalSearch) {
+ throw new Error("You cannot use quotes on type filter");
+ }
+ checkExtraTypeFilterCharacters(parserState);
+ // The type filter doesn't count as an element since it's a modifier.
+ parserState.typeFilter = query.elems.pop().name;
+ parserState.pos += 1;
+ parserState.totalElems = 0;
+ query.literalSearch = false;
+ foundStopChar = true;
+ continue;
+ }
+ if (!foundStopChar) {
+ if (parserState.typeFilter !== null) {
+ throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
+ }
+ throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
+ }
+ before = query.elems.length;
+ getNextElem(query, parserState, query.elems, false);
+ if (query.elems.length === before) {
+ // Nothing was added, weird... Let's increase the position to not remain stuck.
+ parserState.pos += 1;
+ }
+ foundStopChar = false;
+ }
+ while (parserState.pos < parserState.length) {
+ c = parserState.userQuery[parserState.pos];
+ if (isReturnArrow(parserState)) {
+ parserState.pos += 2;
+ // Get returned elements.
+ getItemsBefore(query, parserState, query.returned, "");
+ // Nothing can come afterward!
+ if (query.returned.length === 0) {
+ throw new Error("Expected at least one item after `->`");
+ }
+ break;
+ } else {
+ parserState.pos += 1;
+ }
+ }
+ }
+
+ /**
+ * Takes the user search input and returns an empty `ParsedQuery`.
+ *
+ * @param {string} userQuery
+ *
+ * @return {ParsedQuery}
+ */
+ function newParsedQuery(userQuery) {
+ return {
+ original: userQuery,
+ userQuery: userQuery.toLowerCase(),
+ typeFilter: NO_TYPE_FILTER,
+ elems: [],
+ returned: [],
+ // Total number of "top" elements (does not include generics).
+ foundElems: 0,
+ literalSearch: false,
+ error: null,
+ };
+ }
+
/**
* Build an URL with search parameters.
*
* @param {string} search - The current search being performed.
* @param {string|null} filterCrates - The current filtering crate (if any).
+ *
* @return {string}
*/
function buildUrl(search, filterCrates) {
}
/**
- * Executes the query and returns a list of results for each results tab.
- * @param {Object} query - The user query
- * @param {Array<string>} searchWords - The list of search words to query against
- * @param {string} [filterCrates] - Crate to search in
- * @return {{
- * in_args: Array<?>,
- * returned: Array<?>,
- * others: Array<?>
- * }}
+ * Parses the query.
+ *
+ * The supported syntax by this parser is as follow:
+ *
+ * ident = *(ALPHA / DIGIT / "_")
+ * path = ident *(DOUBLE-COLON ident)
+ * arg = path [generics]
+ * arg-without-generic = path
+ * type-sep = COMMA/WS *(COMMA/WS)
+ * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
+ * nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
+ * *(type-sep arg-without-generic) *(type-sep)
+ * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
+ * CLOSE-ANGLE-BRACKET/EOF
+ * return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
+ *
+ * exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
+ * type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
+ *
+ * query = *WS (exact-search / type-search) *WS
+ *
+ * type-filter = (
+ * "mod" /
+ * "externcrate" /
+ * "import" /
+ * "struct" /
+ * "enum" /
+ * "fn" /
+ * "type" /
+ * "static" /
+ * "trait" /
+ * "impl" /
+ * "tymethod" /
+ * "method" /
+ * "structfield" /
+ * "variant" /
+ * "macro" /
+ * "primitive" /
+ * "associatedtype" /
+ * "constant" /
+ * "associatedconstant" /
+ * "union" /
+ * "foreigntype" /
+ * "keyword" /
+ * "existential" /
+ * "attr" /
+ * "derive" /
+ * "traitalias")
+ *
+ * OPEN-ANGLE-BRACKET = "<"
+ * CLOSE-ANGLE-BRACKET = ">"
+ * COLON = ":"
+ * DOUBLE-COLON = "::"
+ * QUOTE = %x22
+ * COMMA = ","
+ * RETURN-ARROW = "->"
+ *
+ * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+ * DIGIT = %x30-39
+ * WS = %x09 / " "
+ *
+ * @param {string} val - The user query
+ *
+ * @return {ParsedQuery} - The parsed query
*/
- function execQuery(query, searchWords, filterCrates) {
- function itemTypeFromName(typename) {
- for (var i = 0, len = itemTypes.length; i < len; ++i) {
- if (itemTypes[i] === typename) {
- return i;
+ function parseQuery(userQuery) {
+ userQuery = userQuery.trim();
+ var parserState = {
+ length: userQuery.length,
+ pos: 0,
+ // Total number of elements (includes generics).
+ totalElems: 0,
+ genericsElems: 0,
+ typeFilter: null,
+ userQuery: userQuery.toLowerCase(),
+ };
+ var query = newParsedQuery(userQuery);
+
+ try {
+ parseInput(query, parserState);
+ if (parserState.typeFilter !== null) {
+ var typeFilter = parserState.typeFilter;
+ if (typeFilter === "const") {
+ typeFilter = "constant";
}
+ query.typeFilter = itemTypeFromName(typeFilter);
}
- return NO_TYPE_FILTER;
+ } catch (err) {
+ query = newParsedQuery(userQuery);
+ query.error = err.message;
+ query.typeFilter = -1;
+ return query;
}
- var valLower = query.query.toLowerCase(),
- val = valLower,
- typeFilter = itemTypeFromName(query.type),
- results = {}, results_in_args = {}, results_returned = {},
- split = valLower.split("::");
+ if (!query.literalSearch) {
+ // If there is more than one element in the query, we switch to literalSearch in any
+ // case.
+ query.literalSearch = parserState.totalElems > 1;
+ }
+ query.foundElems = query.elems.length + query.returned.length;
+ return query;
+ }
- removeEmptyStringsFromArray(split);
+ /**
+ * Creates the query results.
+ *
+ * @param {Array<Result>} results_in_args
+ * @param {Array<Result>} results_returned
+ * @param {Array<Result>} results_in_args
+ * @param {ParsedQuery} parsedQuery
+ *
+ * @return {ResultsTable}
+ */
+ function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
+ return {
+ "in_args": results_in_args,
+ "returned": results_returned,
+ "others": results_others,
+ "query": parsedQuery,
+ };
+ }
+
+ /**
+ * Executes the parsed query and builds a {ResultsTable}.
+ *
+ * @param {ParsedQuery} parsedQuery - The parsed user query
+ * @param {Object} searchWords - The list of search words to query against
+ * @param {Object} [filterCrates] - Crate to search in if defined
+ *
+ * @return {ResultsTable}
+ */
+ function execQuery(parsedQuery, searchWords, filterCrates) {
+ var results_others = {}, results_in_args = {}, results_returned = {};
function transformResults(results) {
var duplicates = {};
}
function sortResults(results, isType) {
+ var userQuery = parsedQuery.userQuery;
var ar = [];
for (var entry in results) {
if (hasOwnPropertyRustdoc(results, entry)) {
var a, b;
// sort by exact match with regard to the last word (mismatch goes later)
- a = (aaa.word !== val);
- b = (bbb.word !== val);
+ a = (aaa.word !== userQuery);
+ b = (bbb.word !== userQuery);
if (a !== b) { return a - b; }
// Sort by non levenshtein results and then levenshtein results by the distance
return 0;
});
+ var nameSplit = null;
+ if (parsedQuery.elems.length === 1) {
+ var hasPath = typeof parsedQuery.elems[0].path === "undefined";
+ nameSplit = hasPath ? null : parsedQuery.elems[0].path;
+ }
+
for (var i = 0, len = results.length; i < len; ++i) {
result = results[i];
path = result.item.path.toLowerCase(),
parent = result.item.parent;
- if (!isType && !validateResult(name, path, split, parent)) {
+ if (!isType && !validateResult(name, path, nameSplit, parent)) {
result.id = -1;
}
}
return transformResults(results);
}
- function extractGenerics(val) {
- val = val.toLowerCase();
- if (val.indexOf("<") !== -1) {
- var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
- return {
- name: val.substring(0, val.indexOf("<")),
- generics: values.split(/\s*,\s*/),
- };
+ /**
+ * This function checks if the object (`row`) generics match the given type (`elem`)
+ * generics. If there are no generics on `row`, `defaultLev` is returned.
+ *
+ * @param {Row} row - The object to check.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} defaultLev - This is the value to return in case there are no generics.
+ *
+ * @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkGenerics(row, elem, defaultLev) {
+ if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
+ return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
+ } else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
+ if (row.length > GENERICS_DATA) {
+ return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
+ }
+ return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
}
- return {
- name: val,
- generics: [],
- };
- }
-
- function checkGenerics(obj, val) {
// The names match, but we need to be sure that all generics kinda
// match as well.
- var tmp_lev, elem_name;
- if (val.generics.length > 0) {
- if (obj.length > GENERICS_DATA &&
- obj[GENERICS_DATA].length >= val.generics.length) {
- var elems = Object.create(null);
- var elength = obj[GENERICS_DATA].length;
- for (var x = 0; x < elength; ++x) {
- if (!elems[obj[GENERICS_DATA][x][NAME]]) {
- elems[obj[GENERICS_DATA][x][NAME]] = 0;
+ var elem_name;
+ if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
+ var elems = Object.create(null);
+ for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
+ elem_name = row[GENERICS_DATA][x][NAME];
+ if (elem_name === "") {
+ // Pure generic, needs to check into it.
+ if (checkGenerics(
+ row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
+ return MAX_LEV_DISTANCE + 1;
}
- elems[obj[GENERICS_DATA][x][NAME]] += 1;
+ continue;
+ }
+ if (elems[elem_name] === undefined) {
+ elems[elem_name] = 0;
}
- var total = 0;
- var done = 0;
- // We need to find the type that matches the most to remove it in order
- // to move forward.
- var vlength = val.generics.length;
- for (x = 0; x < vlength; ++x) {
- var lev = MAX_LEV_DISTANCE + 1;
- var firstGeneric = val.generics[x];
- var match = null;
- if (elems[firstGeneric]) {
- match = firstGeneric;
- lev = 0;
- } else {
- for (elem_name in elems) {
- tmp_lev = levenshtein(elem_name, firstGeneric);
- if (tmp_lev < lev) {
- lev = tmp_lev;
- match = elem_name;
- }
+ elems[elem_name] += 1;
+ }
+ // We need to find the type that matches the most to remove it in order
+ // to move forward.
+ for (x = 0, length = elem.generics.length; x < length; ++x) {
+ var generic = elem.generics[x];
+ var match = null;
+ if (elems[generic.name]) {
+ match = generic.name;
+ } else {
+ for (elem_name in elems) {
+ if (!hasOwnPropertyRustdoc(elems, elem_name)) {
+ continue;
}
- }
- if (match !== null) {
- elems[match] -= 1;
- if (elems[match] == 0) {
- delete elems[match];
+ if (elem_name === generic) {
+ match = elem_name;
+ break;
}
- total += lev;
- done += 1;
- } else {
- return MAX_LEV_DISTANCE + 1;
}
}
- return Math.ceil(total / done);
+ if (match === null) {
+ return MAX_LEV_DISTANCE + 1;
+ }
+ elems[match] -= 1;
+ if (elems[match] === 0) {
+ delete elems[match];
+ }
}
+ return 0;
}
return MAX_LEV_DISTANCE + 1;
}
/**
- * This function checks if the object (`obj`) matches the given type (`val`) and its
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
+ * generics (if any).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match.
+ */
+ function checkIfInGenerics(row, elem) {
+ var lev = MAX_LEV_DISTANCE + 1;
+ for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
+ lev = Math.min(
+ checkType(row[GENERICS_DATA][x], elem, true),
+ lev
+ );
+ }
+ return lev;
+ }
+
+ /**
+ * This function checks if the object (`row`) matches the given type (`elem`) and its
* generics (if any).
*
- * @param {Object} obj
- * @param {string} val
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
* @param {boolean} literalSearch
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is
* no match, returns `MAX_LEV_DISTANCE + 1`.
*/
- function checkType(obj, val, literalSearch) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
- var tmp_lev = MAX_LEV_DISTANCE + 1;
- var len, x, firstGeneric;
- if (obj[NAME] === val.name) {
- if (literalSearch) {
- if (val.generics && val.generics.length !== 0) {
- if (obj.length > GENERICS_DATA &&
- obj[GENERICS_DATA].length > 0) {
- var elems = Object.create(null);
- len = obj[GENERICS_DATA].length;
- for (x = 0; x < len; ++x) {
- if (!elems[obj[GENERICS_DATA][x][NAME]]) {
- elems[obj[GENERICS_DATA][x][NAME]] = 0;
- }
- elems[obj[GENERICS_DATA][x][NAME]] += 1;
- }
+ function checkType(row, elem, literalSearch) {
+ if (row[NAME].length === 0) {
+ // This is a pure "generic" search, no need to run other checks.
+ if (row.length > GENERICS_DATA) {
+ return checkIfInGenerics(row, elem);
+ }
+ return MAX_LEV_DISTANCE + 1;
+ }
- len = val.generics.length;
- for (x = 0; x < len; ++x) {
- firstGeneric = val.generics[x];
- if (elems[firstGeneric]) {
- elems[firstGeneric] -= 1;
- } else {
- // Something wasn't found and this is a literal search so
- // abort and return a "failing" distance.
- return MAX_LEV_DISTANCE + 1;
- }
- }
- // Everything was found, success!
+ var lev = levenshtein(row[NAME], elem.name);
+ if (literalSearch) {
+ if (lev !== 0) {
+ // The name didn't match, let's try to check if the generics do.
+ if (elem.generics.length === 0) {
+ var checkGeneric = (row.length > GENERICS_DATA &&
+ row[GENERICS_DATA].length > 0);
+ if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
+ return tmp_elem[NAME] === elem.name;
+ }) !== -1) {
return 0;
}
- return MAX_LEV_DISTANCE + 1;
}
- return 0;
- } else {
- // If the type has generics but don't match, then it won't return at this point.
- // Otherwise, `checkGenerics` will return 0 and it'll return.
- if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
- tmp_lev = checkGenerics(obj, val);
- if (tmp_lev <= MAX_LEV_DISTANCE) {
- return tmp_lev;
- }
- }
- }
- } else if (literalSearch) {
- var found = false;
- if ((!val.generics || val.generics.length === 0) &&
- obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
- found = obj[GENERICS_DATA].some(
- function(gen) {
- return gen[NAME] === val.name;
- });
- }
- return found ? 0 : MAX_LEV_DISTANCE + 1;
- }
- lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
- if (lev_distance <= MAX_LEV_DISTANCE) {
- // The generics didn't match but the name kinda did so we give it
- // a levenshtein distance value that isn't *this* good so it goes
- // into the search results but not too high.
- lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
- }
- if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
- // We can check if the type we're looking for is inside the generics!
- var olength = obj[GENERICS_DATA].length;
- for (x = 0; x < olength; ++x) {
- tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+ return MAX_LEV_DISTANCE + 1;
+ } else if (elem.generics.length > 0) {
+ return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
}
- if (tmp_lev !== 0) {
- // If we didn't find a good enough result, we go check inside the generics of
- // the generics.
- for (x = 0; x < olength && tmp_lev !== 0; ++x) {
- tmp_lev = Math.min(
- checkType(obj[GENERICS_DATA][x], val, literalSearch),
- tmp_lev
- );
+ return 0;
+ } else if (row.length > GENERICS_DATA) {
+ if (elem.generics.length === 0) {
+ if (lev === 0) {
+ return 0;
+ }
+ // The name didn't match so we now check if the type we're looking for is inside
+ // the generics!
+ lev = checkIfInGenerics(row, elem);
+ // Now whatever happens, the returned distance is "less good" so we should mark
+ // it as such, and so we add 0.5 to the distance to make it "less good".
+ return lev + 0.5;
+ } else if (lev > MAX_LEV_DISTANCE) {
+ // So our item's name doesn't match at all and has generics.
+ //
+ // Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
+ // looking for "B<C>", we'll need to go down.
+ return checkIfInGenerics(row, elem);
+ } else {
+ // At this point, the name kinda match and we have generics to check, so
+ // let's go!
+ var tmp_lev = checkGenerics(row, elem, lev);
+ if (tmp_lev > MAX_LEV_DISTANCE) {
+ return MAX_LEV_DISTANCE + 1;
}
+ // We compute the median value of both checks and return it.
+ return (tmp_lev + lev) / 2;
}
+ } else if (elem.generics.length > 0) {
+ // In this case, we were expecting generics but there isn't so we simply reject this
+ // one.
+ return MAX_LEV_DISTANCE + 1;
}
- // Now whatever happens, the returned distance is "less good" so we should mark it
- // as such, and so we add 1 to the distance to make it "less good".
- return Math.min(lev_distance, tmp_lev) + 1;
+ // No generics on our query or on the target type so we can return without doing
+ // anything else.
+ return lev;
}
/**
- * This function checks if the object (`obj`) has an argument with the given type (`val`).
+ * This function checks if the object (`row`) has an argument with the given type (`elem`).
*
- * @param {Object} obj
- * @param {string} val
- * @param {boolean} literalSearch
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
* @param {integer} typeFilter
*
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
* match, returns `MAX_LEV_DISTANCE + 1`.
*/
- function findArg(obj, val, literalSearch, typeFilter) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
+ function findArg(row, elem, typeFilter) {
+ var lev = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
- var length = obj.type[INPUTS_DATA].length;
+ if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
+ var length = row.type[INPUTS_DATA].length;
for (var i = 0; i < length; i++) {
- var tmp = obj.type[INPUTS_DATA][i];
+ var tmp = row.type[INPUTS_DATA][i];
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
return 0;
- } else if (literalSearch) {
- continue;
}
- lev_distance = Math.min(tmp, lev_distance);
}
}
- return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
- function checkReturned(obj, val, literalSearch, typeFilter) {
- var lev_distance = MAX_LEV_DISTANCE + 1;
+ /**
+ * This function checks if the object (`row`) returns the given type (`elem`).
+ *
+ * @param {Row} row
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {integer} typeFilter
+ *
+ * @return {integer} - Returns a Levenshtein distance to the best match. If there is no
+ * match, returns `MAX_LEV_DISTANCE + 1`.
+ */
+ function checkReturned(row, elem, typeFilter) {
+ var lev = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
- var ret = obj.type[OUTPUT_DATA];
+ if (row && row.type && row.type.length > OUTPUT_DATA) {
+ var ret = row.type[OUTPUT_DATA];
if (typeof ret[0] === "string") {
ret = [ret];
}
if (!typePassesFilter(typeFilter, tmp[1])) {
continue;
}
- tmp = checkType(tmp, val, literalSearch);
- if (tmp === 0) {
+ lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
+ if (lev === 0) {
return 0;
- } else if (literalSearch) {
- continue;
}
- lev_distance = Math.min(tmp, lev_distance);
}
}
- return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
+ return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
}
function checkPath(contains, lastElem, ty) {
}
function handleAliases(ret, query, filterCrates) {
+ var lowerQuery = query.toLowerCase();
// We separate aliases and crate aliases because we want to have current crate
// aliases to be before the others in the displayed results.
var aliases = [];
var crateAliases = [];
if (filterCrates !== null) {
- if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
- var query_aliases = ALIASES[filterCrates][query.search];
+ if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
+ var query_aliases = ALIASES[filterCrates][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
}
} else {
Object.keys(ALIASES).forEach(function(crate) {
- if (ALIASES[crate][query.search]) {
+ if (ALIASES[crate][lowerQuery]) {
var pushTo = crate === window.currentCrate ? crateAliases : aliases;
- var query_aliases = ALIASES[crate][query.search];
+ var query_aliases = ALIASES[crate][lowerQuery];
var len = query_aliases.length;
for (var i = 0; i < len; ++i) {
pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
aliases.sort(sortFunc);
var pushFunc = function(alias) {
- alias.alias = query.raw;
+ alias.alias = query;
var res = buildHrefAndPath(alias);
alias.displayPath = pathSplitter(res[0]);
alias.fullPath = alias.displayPath + alias.name;
}
/**
- * This function adds the given result into the provided `res` map if it matches the
+ * This function adds the given result into the provided `results` map if it matches the
* following condition:
*
- * * If it is a "literal search" (`isExact`), then `lev` must be 0.
+ * * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
* * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
*
- * The `res` map contains information which will be used to sort the search results:
+ * The `results` map contains information which will be used to sort the search results:
*
- * * `fullId` is a `string`` used as the key of the object we use for the `res` map.
+ * * `fullId` is a `string`` used as the key of the object we use for the `results` map.
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
* * `lev` is the main metric used to sort the search results.
*
- * @param {boolean} isExact
- * @param {Object} res
+ * @param {Results} results
* @param {string} fullId
* @param {integer} id
* @param {integer} index
* @param {integer} lev
*/
- function addIntoResults(isExact, res, fullId, id, index, lev) {
- if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
- if (res[fullId] !== undefined) {
- var result = res[fullId];
+ function addIntoResults(results, fullId, id, index, lev) {
+ if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
+ if (results[fullId] !== undefined) {
+ var result = results[fullId];
if (result.dontValidate || result.lev <= lev) {
return;
}
}
- res[fullId] = {
+ results[fullId] = {
id: id,
index: index,
- dontValidate: isExact,
+ dontValidate: parsedQuery.literalSearch,
lev: lev,
};
}
}
- // quoted values mean literal search
- var nSearchWords = searchWords.length;
- var i, it;
- var ty;
- var fullId;
- var returned;
- var in_args;
- var len;
- if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
- val.charAt(val.length - 1) === val.charAt(0))
- {
- val = extractGenerics(val.substr(1, val.length - 2));
- for (i = 0; i < nSearchWords; ++i) {
- if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
- continue;
+ /**
+ * This function is called in case the query is only one element (with or without generics).
+ * This element will be compared to arguments' and returned values' items and also to items.
+ *
+ * Other important thing to note: since there is only one element, we use levenshtein
+ * distance for name comparisons.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {QueryElement} elem - The element from the parsed query.
+ * @param {Results} results_others - Unqualified results (not in arguments nor in
+ * returned values).
+ * @param {Results} results_in_args - Matching arguments results.
+ * @param {Results} results_returned - Matching returned arguments results.
+ */
+ function handleSingleArg(
+ row,
+ pos,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ ) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
+ var lev, lev_add = 0, index = -1;
+ var fullId = row.id;
+
+ var in_args = findArg(row, elem, parsedQuery.typeFilter);
+ var returned = checkReturned(row, elem, parsedQuery.typeFilter);
+
+ addIntoResults(results_in_args, fullId, pos, index, in_args);
+ addIntoResults(results_returned, fullId, pos, index, returned);
+
+ if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
+ return;
+ }
+ var searchWord = searchWords[pos];
+
+ if (parsedQuery.literalSearch) {
+ if (searchWord === elem.name) {
+ addIntoResults(results_others, fullId, pos, -1, 0);
}
- in_args = findArg(searchIndex[i], val, true, typeFilter);
- returned = checkReturned(searchIndex[i], val, true, typeFilter);
- ty = searchIndex[i];
- fullId = ty.id;
-
- if (searchWords[i] === val.name
- && typePassesFilter(typeFilter, searchIndex[i].ty)) {
- addIntoResults(true, results, fullId, i, -1, 0);
+ return;
+ }
+
+ // No need to check anything else if it's a "pure" generics search.
+ if (elem.name.length === 0) {
+ if (row.type !== null) {
+ lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
+ addIntoResults(results_others, fullId, pos, index, lev);
}
- addIntoResults(true, results_in_args, fullId, i, -1, in_args);
- addIntoResults(true, results_returned, fullId, i, -1, returned);
- }
- query.inputs = [val];
- query.output = val;
- query.search = val;
- // searching by type
- } else if (val.search("->") > -1) {
- var trimmer = function(s) { return s.trim(); };
- var parts = val.split("->").map(trimmer);
- var input = parts[0];
- // sort inputs so that order does not matter
- var inputs = input.split(",").map(trimmer).sort();
- for (i = 0, len = inputs.length; i < len; ++i) {
- inputs[i] = extractGenerics(inputs[i]);
- }
- var output = extractGenerics(parts[1]);
-
- for (i = 0; i < nSearchWords; ++i) {
- if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
- continue;
+ return;
+ }
+
+ if (elem.fullPath.length > 1) {
+ lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
+ if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
+ return;
+ } else if (lev > 0) {
+ lev_add = lev / 10;
}
- var type = searchIndex[i].type;
- ty = searchIndex[i];
- if (!type) {
- continue;
+ }
+
+ if (searchWord.indexOf(elem.pathLast) > -1 ||
+ row.normalizedName.indexOf(elem.pathLast) > -1)
+ {
+ // filter type: ... queries
+ if (!results_others[fullId] !== undefined) {
+ index = row.normalizedName.indexOf(elem.pathLast);
}
- fullId = ty.id;
+ }
+ lev = levenshtein(searchWord, elem.pathLast);
+ lev += lev_add;
+ if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
+ {
+ if (elem.pathLast.length < 6) {
+ lev = 1;
+ } else {
+ lev = 0;
+ }
+ }
+ if (lev > MAX_LEV_DISTANCE) {
+ return;
+ } else if (index !== -1 && elem.fullPath.length < 2) {
+ lev -= 1;
+ }
+ if (lev < 0) {
+ lev = 0;
+ }
+ addIntoResults(results_others, fullId, pos, index, lev);
+ }
- returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
- if (output.name === "*" || returned === 0) {
- in_args = false;
- var is_module = false;
+ /**
+ * This function is called in case the query has more than one element. In this case, it'll
+ * try to match the items which validates all the elements. For `aa -> bb` will look for
+ * functions which have a parameter `aa` and has `bb` in its returned values.
+ *
+ * @param {Row} row
+ * @param {integer} pos - Position in the `searchIndex`.
+ * @param {Object} results
+ */
+ function handleArgs(row, pos, results) {
+ if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+ return;
+ }
- if (input === "*") {
- is_module = true;
+ var totalLev = 0;
+ var nbLev = 0;
+ var lev;
+
+ // If the result is too "bad", we return false and it ends this search.
+ function checkArgs(elems, callback) {
+ for (var i = 0, len = elems.length; i < len; ++i) {
+ var elem = elems[i];
+ // There is more than one parameter to the query so all checks should be "exact"
+ lev = callback(row, elem, NO_TYPE_FILTER);
+ if (lev <= 1) {
+ nbLev += 1;
+ totalLev += lev;
} else {
- var firstNonZeroDistance = 0;
- for (it = 0, len = inputs.length; it < len; it++) {
- var distance = checkType(type, inputs[it], true);
- if (distance > 0) {
- firstNonZeroDistance = distance;
- break;
- }
- }
- in_args = firstNonZeroDistance;
- }
- addIntoResults(true, results_in_args, fullId, i, -1, in_args);
- addIntoResults(true, results_returned, fullId, i, -1, returned);
- if (is_module) {
- addIntoResults(true, results, fullId, i, -1, 0);
+ return false;
}
}
+ return true;
+ }
+ if (!checkArgs(parsedQuery.elems, findArg)) {
+ return;
+ }
+ if (!checkArgs(parsedQuery.returned, checkReturned)) {
+ return;
}
- query.inputs = inputs.map(function(input) {
- return input.name;
- });
- query.output = output.name;
- } else {
- query.inputs = [val];
- query.output = val;
- query.search = val;
- // gather matching search results up to a certain maximum
- val = val.replace(/_/g, "");
-
- var valGenerics = extractGenerics(val);
-
- var paths = valLower.split("::");
- removeEmptyStringsFromArray(paths);
- val = paths[paths.length - 1];
- var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
-
- var lev, j;
- for (j = 0; j < nSearchWords; ++j) {
- ty = searchIndex[j];
- if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
- continue;
- }
- var lev_add = 0;
- if (paths.length > 1) {
- lev = checkPath(contains, paths[paths.length - 1], ty);
- if (lev > MAX_LEV_DISTANCE) {
- continue;
- } else if (lev > 0) {
- lev_add = lev / 10;
- }
- }
- returned = MAX_LEV_DISTANCE + 1;
- in_args = MAX_LEV_DISTANCE + 1;
- var index = -1;
- // we want lev results to go lower than others
- lev = MAX_LEV_DISTANCE + 1;
- fullId = ty.id;
+ if (nbLev === 0) {
+ return;
+ }
+ lev = Math.round(totalLev / nbLev);
+ addIntoResults(results, row.id, pos, 0, lev);
+ }
- if (searchWords[j].indexOf(split[i]) > -1 ||
- searchWords[j].indexOf(val) > -1 ||
- ty.normalizedName.indexOf(val) > -1)
- {
- // filter type: ... queries
- if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
- index = ty.normalizedName.indexOf(val);
+ function innerRunQuery() {
+ var elem, i, nSearchWords, in_returned, row;
+
+ if (parsedQuery.foundElems === 1) {
+ if (parsedQuery.elems.length === 1) {
+ elem = parsedQuery.elems[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ // It means we want to check for this element everywhere (in names, args and
+ // returned).
+ handleSingleArg(
+ searchIndex[i],
+ i,
+ elem,
+ results_others,
+ results_in_args,
+ results_returned
+ );
}
- }
- if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
- if (typePassesFilter(typeFilter, ty.ty)) {
- lev += 1;
- } else {
- lev = MAX_LEV_DISTANCE + 1;
+ } else if (parsedQuery.returned.length === 1) {
+ // We received one returned argument to check, so looking into returned values.
+ elem = parsedQuery.returned[0];
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ row = searchIndex[i];
+ in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
+ addIntoResults(results_returned, row.id, i, -1, in_returned);
}
}
- in_args = findArg(ty, valGenerics, false, typeFilter);
- returned = checkReturned(ty, valGenerics, false, typeFilter);
-
- lev += lev_add;
- if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
- if (val.length < 6) {
- lev -= 1;
- } else {
- lev = 0;
- }
+ } else if (parsedQuery.foundElems > 0) {
+ var container = results_others;
+ // In the special case where only a "returned" information is available, we want to
+ // put the information into the "results_returned" dict.
+ if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
+ container = results_returned;
}
- addIntoResults(false, results_in_args, fullId, j, index, in_args);
- addIntoResults(false, results_returned, fullId, j, index, returned);
- if (typePassesFilter(typeFilter, ty.ty) &&
- (index !== -1 || lev <= MAX_LEV_DISTANCE)) {
- if (index !== -1 && paths.length < 2) {
- lev = 0;
- }
- addIntoResults(false, results, fullId, j, index, lev);
+ for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
+ handleArgs(searchIndex[i], i, container);
}
}
}
- var ret = {
- "in_args": sortResults(results_in_args, true),
- "returned": sortResults(results_returned, true),
- "others": sortResults(results, false),
- };
- handleAliases(ret, query, filterCrates);
+ if (parsedQuery.error === null) {
+ innerRunQuery();
+ }
+
+ var ret = createQueryResults(
+ sortResults(results_in_args, true),
+ sortResults(results_returned, true),
+ sortResults(results_others, false),
+ parsedQuery);
+ handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
+ if (parsedQuery.error !== null && ret.others.length !== 0) {
+ // It means some doc aliases were found so let's "remove" the error!
+ ret.query.error = null;
+ }
return ret;
}
* @param {string} path - The path of the result
* @param {string} keys - The keys to be used (["file", "open"])
* @param {Object} parent - The parent of the result
+ *
* @return {boolean} - Whether the result is valid or not
*/
function validateResult(name, path, keys, parent) {
+ if (!keys || !keys.length) {
+ return true;
+ }
for (var i = 0, len = keys.length; i < len; ++i) {
// each check is for validation so we negate the conditions and invalidate
if (!(
return true;
}
- /**
- * Parse a string into a query object.
- *
- * @param {string} raw - The text that the user typed.
- * @returns {ParsedQuery}
- */
- function getQuery(raw) {
- var matches, type = "", query;
- query = raw;
-
- matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
- if (matches) {
- type = matches[1].replace(/^const$/, "constant");
- query = query.substring(matches[0].length);
- }
-
- return {
- raw: raw,
- query: query,
- type: type,
- id: query + type
- };
- }
-
function nextTab(direction) {
var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
link.appendChild(wrapper);
output.appendChild(link);
});
- } else {
+ } else if (query.error === null) {
output.className = "search-failed" + extraClass;
output.innerHTML = "No results :(<br/>" +
"Try on <a href=\"https://duckduckgo.com/?q=" +
- encodeURIComponent("rust " + query.query) +
+ encodeURIComponent("rust " + query.userQuery) +
"\">DuckDuckGo</a>?<br/><br/>" +
"Or try looking in one of these:<ul><li>The <a " +
"href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
}
+ /**
+ * @param {ResultsTable} results
+ * @param {boolean} go_to_first
+ * @param {string} filterCrates
+ */
function showResults(results, go_to_first, filterCrates) {
var search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
elem.click();
return;
}
- var query = getQuery(searchState.input.value);
+ if (results.query === undefined) {
+ results.query = parseQuery(searchState.input.value);
+ }
- currentResults = query.id;
+ currentResults = results.query.userQuery;
- var ret_others = addTab(results.others, query, true);
- var ret_in_args = addTab(results.in_args, query, false);
- var ret_returned = addTab(results.returned, query, false);
+ var ret_others = addTab(results.others, results.query, true);
+ var ret_in_args = addTab(results.in_args, results.query, false);
+ var ret_returned = addTab(results.returned, results.query, false);
// Navigate to the relevant tab if the current tab is empty, like in case users search
// for "-> String". If they had selected another tab previously, they have to click on
}
crates += `</select>`;
}
- var output = `<div id="search-settings">
- <h1 class="search-results-title">Results for ${escape(query.query)} ` +
- (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
- crates +
- `</div><div id="titles">` +
+
+ var typeFilter = "";
+ if (results.query.typeFilter !== NO_TYPE_FILTER) {
+ typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ }
+
+ var output = `<div id="search-settings">` +
+ `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
+ `${typeFilter}</h1> in ${crates} </div>`;
+ if (results.query.error !== null) {
+ output += `<h3>Query parser error: "${results.query.error}".</h3>`;
+ }
+ output += `<div id="titles">` +
makeTabHeader(0, "In Names", ret_others[1]) +
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
makeTabHeader(2, "In Return Types", ret_returned[1]) +
printTab(currentTab);
}
- function execSearch(query, searchWords, filterCrates) {
- query = query.raw.trim();
- var results = {
- "in_args": [],
- "returned": [],
- "others": [],
- };
-
- if (query.length !== 0) {
- var tmp = execQuery(getQuery(query), searchWords, filterCrates);
-
- results.in_args.push(tmp.in_args);
- results.returned.push(tmp.returned);
- results.others.push(tmp.others);
- }
- return {
- "in_args": results.in_args[0],
- "returned": results.returned[0],
- "others": results.others[0],
- };
- }
-
/**
* Perform a search based on the current state of the search input element
* and display the results.
*/
function search(e, forced) {
var params = searchState.getQueryStringParams();
- var query = getQuery(searchState.input.value.trim());
+ var query = parseQuery(searchState.input.value.trim());
if (e) {
e.preventDefault();
}
- if (query.query.length === 0) {
- return;
- }
- if (!forced && query.id === currentResults) {
- if (query.query.length > 0) {
+ if (!forced && query.userQuery === currentResults) {
+ if (query.userQuery.length > 0) {
putBackSearch();
}
return;
}
// Update document title to maintain a meaningful browser history
- searchState.title = "Results for " + query.query + " - Rust";
+ searchState.title = "Results for " + query.original + " - Rust";
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (searchState.browserSupportsHistoryApi()) {
- var newURL = buildUrl(query.raw, filterCrates);
-
+ var newURL = buildUrl(query.original, filterCrates);
if (!history.state && !params.search) {
history.pushState(null, "", newURL);
} else {
}
}
- showResults(execSearch(query, searchWords, filterCrates),
- params["go_to_first"], filterCrates);
+ showResults(
+ execQuery(query, searchWords, filterCrates),
+ params.go_to_first,
+ filterCrates);
}
function buildIndex(rawSearchIndex) {
use rustc_ast::ast;
use rustc_hir::{def::CtorKind, def_id::DefId};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::Pos;
use rustc_target::spec::abi::Abi as RustcAbi;
match v {
Public => Visibility::Public,
Inherited => Visibility::Default,
- Restricted(did) if did.index == CRATE_DEF_INDEX => Visibility::Crate,
+ Restricted(did) if did.is_crate_root() => Visibility::Crate,
Restricted(did) => Visibility::Restricted {
parent: from_item_id(did.into()),
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
//! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
use pulldown_cmark::LinkType;
+use rustc_ast::util::comments::may_have_doc_links;
use rustc_data_structures::{fx::FxHashMap, intern::Interned, stable_set::FxHashSet};
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir::def::Namespace::*;
}
/// A link failed to resolve.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum ResolutionFailure<'a> {
/// This resolved, but with the wrong namespace.
WrongNamespace {
Dummy,
}
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum MalformedGenerics {
/// This link has unbalanced angle brackets.
///
}
}
+#[derive(Clone, Copy)]
enum AnchorFailure {
/// User error: `[std#x#y]` is not valid
MultipleAnchors,
// Resolver doesn't know about true, false, and types that aren't paths (e.g. `()`).
let result = self
.cx
- .enter_resolver(|resolver| resolver.resolve_rustdoc_path(path_str, ns, module_id))
+ .resolver_caches
+ .doc_link_resolutions
+ .get(&(Symbol::intern(path_str), ns, module_id))
+ .copied()
+ .unwrap_or_else(|| {
+ self.cx.enter_resolver(|resolver| {
+ resolver.resolve_rustdoc_path(path_str, ns, module_id)
+ })
+ })
.and_then(|res| res.try_into().ok())
.or_else(|| resolve_primitive(path_str, ns))
.or_else(|| self.resolve_macro_rules(path_str, ns));
// In the presence of re-exports, this is not the same as the module of the item.
// Rather than merging all documentation into one, resolve it one attribute at a time
// so we know which module it came from.
- for (parent_module, doc) in item.attrs.collapsed_doc_value_by_module_level() {
+ for (parent_module, doc) in item.attrs.prepare_to_doc_link_resolution() {
+ if !may_have_doc_links(&doc) {
+ continue;
+ }
debug!("combined_docs={}", doc);
// NOTE: if there are links that start in one crate and end in another, this will not resolve them.
// This is a degenerate case and it's not supported by rustdoc.
let parent_node = parent_module.or(parent_node);
- for md_link in markdown_links(&doc) {
+ let mut tmp_links = self
+ .cx
+ .resolver_caches
+ .markdown_links
+ .take()
+ .expect("`markdown_links` are already borrowed");
+ if !tmp_links.contains_key(&doc) {
+ tmp_links.insert(doc.clone(), preprocessed_markdown_links(&doc));
+ }
+ for md_link in &tmp_links[&doc] {
let link = self.resolve_link(&item, &doc, parent_node, md_link);
if let Some(link) = link {
self.cx.cache.intra_doc_links.entry(item.item_id).or_default().push(link);
}
}
+ self.cx.resolver_caches.markdown_links = Some(tmp_links);
}
if item.is_mod() {
}
}
-enum PreprocessingError<'a> {
+enum PreprocessingError {
Anchor(AnchorFailure),
Disambiguator(Range<usize>, String),
- Resolution(ResolutionFailure<'a>, String, Option<Disambiguator>),
+ Resolution(ResolutionFailure<'static>, String, Option<Disambiguator>),
}
-impl From<AnchorFailure> for PreprocessingError<'_> {
+impl From<AnchorFailure> for PreprocessingError {
fn from(err: AnchorFailure) -> Self {
Self::Anchor(err)
}
}
+#[derive(Clone)]
struct PreprocessingInfo {
path_str: String,
disambiguator: Option<Disambiguator>,
link_text: String,
}
+// Not a typedef to avoid leaking several private structures from this module.
+crate struct PreprocessedMarkdownLink(Result<PreprocessingInfo, PreprocessingError>, MarkdownLink);
+
/// Returns:
/// - `None` if the link should be ignored.
/// - `Some(Err)` if the link should emit an error
/// - `Some(Ok)` if the link is valid
///
/// `link_buffer` is needed for lifetime reasons; it will always be overwritten and the contents ignored.
-fn preprocess_link<'a>(
- ori_link: &'a MarkdownLink,
-) -> Option<Result<PreprocessingInfo, PreprocessingError<'a>>> {
+fn preprocess_link(
+ ori_link: &MarkdownLink,
+) -> Option<Result<PreprocessingInfo, PreprocessingError>> {
// [] is mostly likely not supposed to be a link
if ori_link.link.is_empty() {
return None;
}))
}
+fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
+ markdown_links(s, |link| {
+ preprocess_link(&link).map(|pp_link| PreprocessedMarkdownLink(pp_link, link))
+ })
+}
+
impl LinkCollector<'_, '_> {
/// This is the entry point for resolving an intra-doc link.
///
item: &Item,
dox: &str,
parent_node: Option<DefId>,
- ori_link: MarkdownLink,
+ link: &PreprocessedMarkdownLink,
) -> Option<ItemLink> {
+ let PreprocessedMarkdownLink(pp_link, ori_link) = link;
trace!("considering link '{}'", ori_link.link);
let diag_info = DiagnosticInfo {
link_range: ori_link.range.clone(),
};
- let PreprocessingInfo { ref path_str, disambiguator, extra_fragment, link_text } =
- match preprocess_link(&ori_link)? {
- Ok(x) => x,
- Err(err) => {
- match err {
- PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, err),
- PreprocessingError::Disambiguator(range, msg) => {
- disambiguator_error(self.cx, diag_info, range, &msg)
- }
- PreprocessingError::Resolution(err, path_str, disambiguator) => {
- resolution_failure(
- self,
- diag_info,
- &path_str,
- disambiguator,
- smallvec![err],
- );
- }
+ let PreprocessingInfo { path_str, disambiguator, extra_fragment, link_text } = match pp_link
+ {
+ Ok(x) => x,
+ Err(err) => {
+ match err {
+ PreprocessingError::Anchor(err) => anchor_failure(self.cx, diag_info, *err),
+ PreprocessingError::Disambiguator(range, msg) => {
+ disambiguator_error(self.cx, diag_info, range.clone(), msg)
+ }
+ PreprocessingError::Resolution(err, path_str, disambiguator) => {
+ resolution_failure(
+ self,
+ diag_info,
+ path_str,
+ *disambiguator,
+ smallvec![err.clone()],
+ );
}
- return None;
}
- };
+ return None;
+ }
+ };
+ let disambiguator = *disambiguator;
let inner_docs = item.inner_docs(self.cx.tcx);
module_id,
dis: disambiguator,
path_str: path_str.to_owned(),
- extra_fragment,
+ extra_fragment: extra_fragment.clone(),
},
diag_info.clone(), // this struct should really be Copy, but Range is not :(
matches!(ori_link.kind, LinkType::Reference | LinkType::Shortcut),
}
Some(ItemLink {
- link: ori_link.link,
- link_text,
+ link: ori_link.link.clone(),
+ link_text: link_text.clone(),
did: res.def_id(self.cx.tcx),
fragment,
})
&diag_info,
)?;
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
- Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
+ Some(ItemLink {
+ link: ori_link.link.clone(),
+ link_text: link_text.clone(),
+ did: id,
+ fragment,
+ })
}
}
}
use crate::clean::Attributes;
use crate::core::ResolverCaches;
-use crate::html::markdown::markdown_links;
-use crate::passes::collect_intra_doc_links::preprocess_link;
+use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
+use crate::passes::collect_intra_doc_links::PreprocessedMarkdownLink;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, ItemKind};
use rustc_ast_lowering::ResolverAstLowering;
-use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def::{DefKind, Res};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::Namespace::*;
+use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
use rustc_hir::TraitCandidate;
use rustc_middle::ty::{DefIdTree, Visibility};
use rustc_resolve::{ParentScope, Resolver};
use rustc_session::config::Externs;
-use rustc_span::SyntaxContext;
+use rustc_span::{Symbol, SyntaxContext};
use std::collections::hash_map::Entry;
use std::mem;
resolver,
current_mod: CRATE_DEF_ID,
visited_mods: Default::default(),
+ markdown_links: Default::default(),
+ doc_link_resolutions: Default::default(),
traits_in_scope: Default::default(),
all_traits: Default::default(),
all_trait_impls: Default::default(),
// Overridden `visit_item` below doesn't apply to the crate root,
// so we have to visit its attributes and reexports separately.
- link_resolver.load_links_in_attrs(&krate.attrs);
+ link_resolver.resolve_doc_links_local(&krate.attrs);
link_resolver.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
visit::walk_crate(&mut link_resolver, krate);
link_resolver.process_extern_impls();
}
ResolverCaches {
+ markdown_links: Some(link_resolver.markdown_links),
+ doc_link_resolutions: link_resolver.doc_link_resolutions,
traits_in_scope: link_resolver.traits_in_scope,
all_traits: Some(link_resolver.all_traits),
all_trait_impls: Some(link_resolver.all_trait_impls),
}
}
+fn doc_attrs<'a>(attrs: impl Iterator<Item = &'a ast::Attribute>) -> Attributes {
+ let mut attrs = Attributes::from_ast_iter(attrs.map(|attr| (attr, None)), true);
+ attrs.unindent_doc_comments();
+ attrs
+}
+
struct EarlyDocLinkResolver<'r, 'ra> {
resolver: &'r mut Resolver<'ra>,
current_mod: LocalDefId,
visited_mods: DefIdSet,
+ markdown_links: FxHashMap<String, Vec<PreprocessedMarkdownLink>>,
+ doc_link_resolutions: FxHashMap<(Symbol, Namespace, DefId), Option<Res<ast::NodeId>>>,
traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
all_traits: Vec<DefId>,
all_trait_impls: Vec<DefId>,
}
}
- fn add_traits_in_parent_scope(&mut self, def_id: DefId) {
- if let Some(module_id) = self.resolver.parent(def_id) {
- self.add_traits_in_scope(module_id);
- }
- }
-
/// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
/// That pass filters impls using type-based information, but we don't yet have such
/// information here, so we just conservatively calculate traits in scope for *all* modules
/// having impls in them.
fn process_extern_impls(&mut self) {
- // FIXME: Need to resolve doc links on all these impl and trait items below.
// Resolving links in already existing crates may trigger loading of new crates.
let mut start_cnum = 0;
loop {
// the current crate, and links in their doc comments are not resolved.
for &def_id in &all_traits {
if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
- self.add_traits_in_parent_scope(def_id);
+ self.resolve_doc_links_extern_impl(def_id, false);
}
}
for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
== Visibility::Public
})
{
- self.add_traits_in_parent_scope(impl_def_id);
+ self.resolve_doc_links_extern_impl(impl_def_id, false);
}
}
for (ty_def_id, impl_def_id) in all_inherent_impls {
if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
{
- self.add_traits_in_parent_scope(impl_def_id);
+ self.resolve_doc_links_extern_impl(impl_def_id, true);
}
}
- for def_id in all_incoherent_impls {
- self.add_traits_in_parent_scope(def_id);
+ for impl_def_id in all_incoherent_impls {
+ self.resolve_doc_links_extern_impl(impl_def_id, true);
}
self.all_traits.extend(all_traits);
}
}
- fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute]) {
+ fn resolve_doc_links_extern_impl(&mut self, def_id: DefId, _is_inherent: bool) {
+ // FIXME: Resolve links in associated items in addition to traits themselves,
+ // `force` is used to provide traits in scope for the associated items.
+ self.resolve_doc_links_extern_outer(def_id, def_id, true);
+ }
+
+ fn resolve_doc_links_extern_outer(&mut self, def_id: DefId, scope_id: DefId, force: bool) {
+ if !force && !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+ return;
+ }
+ // FIXME: actually resolve links, not just add traits in scope.
+ if let Some(parent_id) = self.resolver.parent(scope_id) {
+ self.add_traits_in_scope(parent_id);
+ }
+ }
+
+ fn resolve_doc_links_extern_inner(&mut self, def_id: DefId) {
+ if !self.resolver.cstore().may_have_doc_links_untracked(def_id) {
+ return;
+ }
+ // FIXME: actually resolve links, not just add traits in scope.
+ self.add_traits_in_scope(def_id);
+ }
+
+ fn resolve_doc_links_local(&mut self, attrs: &[ast::Attribute]) {
+ if !attrs.iter().any(|attr| attr.may_have_doc_links()) {
+ return;
+ }
let module_id = self.current_mod.to_def_id();
+ self.resolve_doc_links(doc_attrs(attrs.iter()), module_id);
+ }
+
+ fn resolve_doc_links(&mut self, attrs: Attributes, module_id: DefId) {
let mut need_traits_in_scope = false;
- for (doc_module, doc) in
- Attributes::from_ast(attrs, None).collapsed_doc_value_by_module_level()
- {
+ for (doc_module, doc) in attrs.prepare_to_doc_link_resolution() {
assert_eq!(doc_module, None);
- for link in markdown_links(&doc.as_str()) {
- if let Some(Ok(pinfo)) = preprocess_link(&link) {
- self.resolver.resolve_rustdoc_path(&pinfo.path_str, TypeNS, module_id);
+ let links = self
+ .markdown_links
+ .entry(doc)
+ .or_insert_with_key(|doc| preprocessed_markdown_links(doc));
+ for PreprocessedMarkdownLink(pp_link, _) in links {
+ if let Ok(pinfo) = pp_link {
+ // FIXME: Resolve the path in all namespaces and resolve its prefixes too.
+ let ns = TypeNS;
+ self.doc_link_resolutions
+ .entry((Symbol::intern(&pinfo.path_str), ns, module_id))
+ .or_insert_with_key(|(path, ns, module_id)| {
+ self.resolver.resolve_rustdoc_path(path.as_str(), *ns, *module_id)
+ });
need_traits_in_scope = true;
}
}
&& module_id.is_local()
{
if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
- // FIXME: Need to resolve doc links on all these extern items
- // reached through reexports.
let scope_id = match child.res {
Res::Def(DefKind::Variant, ..) => self.resolver.parent(def_id).unwrap(),
_ => def_id,
};
- self.add_traits_in_parent_scope(scope_id); // Outer attribute scope
+ self.resolve_doc_links_extern_outer(def_id, scope_id, false); // Outer attribute scope
if let Res::Def(DefKind::Mod, ..) = child.res {
- self.add_traits_in_scope(def_id); // Inner attribute scope
+ self.resolve_doc_links_extern_inner(def_id); // Inner attribute scope
}
// Traits are processed in `add_extern_traits_in_scope`.
if let Res::Def(DefKind::Mod | DefKind::Enum, ..) = child.res {
impl Visitor<'_> for EarlyDocLinkResolver<'_, '_> {
fn visit_item(&mut self, item: &ast::Item) {
- self.load_links_in_attrs(&item.attrs); // Outer attribute scope
+ self.resolve_doc_links_local(&item.attrs); // Outer attribute scope
if let ItemKind::Mod(..) = item.kind {
let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
- self.load_links_in_attrs(&item.attrs); // Inner attribute scope
+ self.resolve_doc_links_local(&item.attrs); // Inner attribute scope
self.process_module_children_or_reexports(self.current_mod.to_def_id());
visit::walk_item(self, item);
self.current_mod = old_mod;
}
fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
- self.load_links_in_attrs(&item.attrs);
+ self.resolve_doc_links_local(&item.attrs);
visit::walk_assoc_item(self, item, ctxt)
}
fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
- self.load_links_in_attrs(&item.attrs);
+ self.resolve_doc_links_local(&item.attrs);
visit::walk_foreign_item(self, item)
}
fn visit_variant(&mut self, v: &ast::Variant) {
- self.load_links_in_attrs(&v.attrs);
+ self.resolve_doc_links_local(&v.attrs);
visit::walk_variant(self, v)
}
fn visit_field_def(&mut self, field: &ast::FieldDef) {
- self.load_links_in_attrs(&field.attrs);
+ self.resolve_doc_links_local(&field.attrs);
visit::walk_field_def(self, field)
}
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId};
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
use rustc_middle::ty::TyCtxt;
}
crate fn visit_lib(&mut self, cnum: CrateNum) {
- let did = DefId { krate: cnum, index: CRATE_DEF_INDEX };
+ let did = cnum.as_def_id();
self.update(did, Some(AccessLevel::Public));
self.visit_mod(did);
}
-Subproject commit 9168e236c548d1d0e9938ee6dd4cdbd308fdfd72
+Subproject commit fd336816c3a6d228dcef22171c43140f6fa7656f
use std::arch::asm;
// CHECK-LABEL: @clobber_sysv64
-// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_sysv64() {
asm!("", clobber_abi("sysv64"));
}
// CHECK-LABEL: @clobber_win64
-// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: ={ax},={cx},={dx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_win64() {
asm!("", clobber_abi("win64"));
}
// CHECK-LABEL: @clobber_sysv64
-// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={si},={di},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_sysv64_edx() {
let foo: i32;
}
// CHECK-LABEL: @clobber_win64
-// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
+// CHECK: =&{dx},={ax},={cx},={r8},={r9},={r10},={r11},={xmm0},={xmm1},={xmm2},={xmm3},={xmm4},={xmm5},={xmm6},={xmm7},={xmm8},={xmm9},={xmm10},={xmm11},={xmm12},={xmm13},={xmm14},={xmm15},~{xmm16},~{xmm17},~{xmm18},~{xmm19},~{xmm20},~{xmm21},~{xmm22},~{xmm23},~{xmm24},~{xmm25},~{xmm26},~{xmm27},~{xmm28},~{xmm29},~{xmm30},~{xmm31},~{k0},~{k1},~{k2},~{k3},~{k4},~{k5},~{k6},~{k7},~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{dirflag},~{fpsr},~{flags},~{memory}
#[no_mangle]
pub unsafe fn clobber_win64_edx() {
let foo: i32;
#[no_mangle]
fn into_error(self, error: Self::Source) -> Error {
Error::Api {
- source: (|v| v)(error),
+ source: error,
}
}
}
+// min-llvm-version: 14.0
// ignore-debug: the debug assertions get in the way
-// compile-flags: -O
+// compile-flags: -O -Z merge-functions=disabled
#![crate_type = "lib"]
// Ensure that trivial casts of vec elements are O(1)
-// CHECK-LABEL: @vec_iterator_cast
+pub struct Wrapper<T>(T);
+
+#[repr(C)]
+pub struct Foo {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+}
+
+// Going from an aggregate struct to another type currently requires Copy to
+// enable the TrustedRandomAccess specialization. Without it optimizations do not yet
+// reliably recognize the loops as noop for for repr(C) or non-Copy structs.
+#[derive(Copy, Clone)]
+pub struct Bar {
+ a: u64,
+ b: u64,
+ c: u64,
+ d: u64,
+}
+
+// CHECK-LABEL: @vec_iterator_cast_primitive
+#[no_mangle]
+pub fn vec_iterator_cast_primitive(vec: Vec<i8>) -> Vec<u8> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| e as u8).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrapper
+#[no_mangle]
+pub fn vec_iterator_cast_wrapper(vec: Vec<u8>) -> Vec<Wrapper<u8>> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| Wrapper(e)).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+ vec.into_iter().map(|e| e.0).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_aggregate
#[no_mangle]
-pub fn vec_iterator_cast(vec: Vec<isize>) -> Vec<usize> {
+pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
// CHECK-NOT: loop
// CHECK-NOT: call
- vec.into_iter().map(|e| e as usize).collect()
+ vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_deaggregate
+#[no_mangle]
+pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> {
+ // CHECK-NOT: loop
+ // CHECK-NOT: call
+
+ // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
+ // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
+ // the UCG may add additional guarantees for homogenous types in the future that would make this
+ // correct.
+ vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
}
fn h() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
-+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
++ let mut _2: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ let mut _3: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
++ let mut _11: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
-+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
-+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ let mut _6: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
++ debug f => _3; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
++ let _4: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++ let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
++ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
++ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
+ scope 2 {
-+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let _5: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug a => _4; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
++ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
+ scope 3 {
-+ debug b => _5; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
+ }
+ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-- _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+- call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++ _3 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
// mir::Constant
- // + span: $DIR/inline-diverging.rs:22:5: 22:15
- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
- // mir::Constant
// + span: $DIR/inline-diverging.rs:22:16: 22:21
// + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
-+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ StorageLive(_9); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+ _9 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
++ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ _5 = &_3; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
++ StorageLive(_10); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++ _10 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
- }
-
- bb1: {
-- StorageDead(_1); // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
-- _0 = const (); // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
-- return; // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
++ }
++
++ bb1: {
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
}
}
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
_3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
- _2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
+ transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
// mir::Constant
// + span: $DIR/issue-72181-1.rs:17:9: 17:40
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
| '_#2r live at {bb0[0..=1]}
| '_#3r live at {bb0[0..=1]}
| '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
-| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
-| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
-| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
-| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
+| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
|
fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
| '_#3r live at {bb1[0]}
| '_#4r live at {bb1[1..=3]}
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0])
-| '_#4r: '_#5r due to Assignment at Single(bb1[3])
+| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
| '_#1r live at {bb0[0..=22]}
| '_#3r live at {bb0[10]}
| '_#4r live at {bb0[11]}
-| '_#3r: '_#4r due to Assignment at Single(bb0[10])
+| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
// exact-check
-const QUERY = 'hashmap';
+const QUERY = '"hashmap"';
const FILTER_CRATE = 'core';
const EXPECTED = {
--- /dev/null
+const QUERY = [
+ '<P>',
+ '-> <P>',
+ 'a<"P">',
+ '"P" "P"',
+ 'P "P"',
+ '"p" p',
+ '"const": p',
+ "a<:a>",
+ "a<::a>",
+ "((a))",
+ "(p -> p",
+ "::a::b",
+ "a::::b",
+ "a::b::",
+ ":a",
+ "a b:",
+ "a (b:",
+ "_:",
+ "a-bb",
+ "a>bb",
+ "ab'",
+ "a->",
+ '"p" <a>',
+ '"p" a<a>',
+ "a,<",
+ "aaaaa<>b",
+ "fn:aaaaa<>b",
+ "->a<>b",
+ "a<->",
+ "a:: a",
+ "a ::a",
+ "a<a>:",
+ "a<>:",
+ "a,:",
+ " a<> :",
+ "mod : :",
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: "<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "<p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "-> <P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "-> <p>",
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<\"P\">",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<\"p\">",
+ error: "`\"` cannot be used in generics",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"P\" \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" \"p\"",
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "P \"P\"",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p \"p\"",
+ error: "Cannot use literal search when there is more than one element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"p\" p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"p\" p",
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "\"const\": p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "\"const\": p",
+ error: "You cannot use quotes on type filter",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<:a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<:a>",
+ error: "Unexpected `:` after `<`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<::a>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<::a>",
+ error: "Unexpected `::`: paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "((a))",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "((a))",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "(p -> p",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "(p -> p",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "::a::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "::a::b",
+ error: "Paths cannot start with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::::b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::::b",
+ error: "Unexpected `::::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a::b::",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b::",
+ error: "Paths cannot end with `::`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ":a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ":a",
+ error: "Expected type filter before `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b:",
+ error: "Unexpected `:`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a (b:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a (b:",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "_:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "_:",
+ error: "Unknown type filter `_`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a-bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a-bb",
+ error: "Unexpected `-` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a>bb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a>bb",
+ error: "Unexpected `>` (did you mean `->`?)",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "ab'",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "ab'",
+ error: "Unexpected `'`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a->",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a->",
+ error: "Expected at least one item after `->`",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" <a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" <a>',
+ error: "Found generics without a path",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" a<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" a<a>',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a,<',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a,<',
+ error: 'Found generics without a path',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'aaaaa<>b',
+ error: 'Expected `,`, ` `, `:` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'fn:aaaaa<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'fn:aaaaa<>b',
+ error: 'Expected `,`, ` ` or `->`, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->a<>b',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->a<>b',
+ error: 'Expected `,` or ` `, found `b`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a<->',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<->',
+ error: 'Unexpected `-` after `<`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a:: a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a:: a',
+ error: 'Paths cannot end with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'a ::a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a ::a',
+ error: 'Paths cannot start with `::`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<a>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<a>:",
+ error: 'Unexpected `:`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<>:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<>:",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,:",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,:",
+ error: 'Unexpected `,` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a<> :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<> :",
+ error: 'Unexpected `<` in type filter',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "mod : :",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod : :",
+ error: 'Unexpected `:`',
+ },
+];
--- /dev/null
+const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "fn:foo",
+ returned: [],
+ typeFilter: 5,
+ userQuery: "fn:foo",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "foo",
+ fullPath: ["foo"],
+ pathWithoutLast: [],
+ pathLast: "foo",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "enum : foo",
+ returned: [],
+ typeFilter: 4,
+ userQuery: "enum : foo",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "macro<f>:foo",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "macro<f>:foo",
+ error: "Unexpected `:`",
+ },
+];
--- /dev/null
+const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>'];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'A<B<C<D>, E>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a<b<c<d>, e>',
+ error: 'Unexpected `<` after `<`',
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ {
+ name: "u8",
+ fullPath: ["u8"],
+ pathWithoutLast: [],
+ pathLast: "u8",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "p<> u8",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "p<> u8",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: '"p"<a>',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p"<a>',
+ error: null,
+ },
+];
--- /dev/null
+const QUERY = ['R<P>'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "r",
+ fullPath: ["r"],
+ pathWithoutLast: [],
+ pathLast: "r",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ foundElems: 1,
+ original: "R<P>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "r<p>",
+ error: null,
+ }
+];
--- /dev/null
+const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a'];
+
+const PARSED = [
+ {
+ elems: [{
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "A::B",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a::b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b,c',
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a::b",
+ fullPath: ["a", "b"],
+ pathWithoutLast: ["a"],
+ pathLast: "b",
+ generics: [
+ {
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [],
+ },
+ ],
+ },
+ {
+ name: "c",
+ fullPath: ["c"],
+ pathWithoutLast: [],
+ pathLast: "c",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: 'A::B<f>,C',
+ returned: [],
+ typeFilter: -1,
+ userQuery: 'a::b<f>,c',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "mod::a",
+ fullPath: ["mod", "a"],
+ pathWithoutLast: ["mod"],
+ pathLast: "a",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: "mod::a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "mod::a",
+ error: null,
+ },
+];
--- /dev/null
+const QUERY = [
+ '-> "p"',
+ '"p",',
+ '"p" -> a',
+ '"a" -> "p"',
+ '->"-"',
+ '"a',
+ '""',
+];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: '-> "p"',
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: '-> "p"',
+ error: null,
+ },
+ {
+ elems: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ foundElems: 1,
+ original: '"p",',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p",',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"p" -> a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"p" -> a',
+ error: "You cannot have more than one element if you use quotes",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a" -> "p"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a" -> "p"',
+ error: "Cannot have more than one literal search element",
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '->"-"',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '->"-"',
+ error: 'Unexpected `-` in a string element',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '"a',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '"a',
+ error: 'Unclosed `"`',
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: '""',
+ returned: [],
+ typeFilter: -1,
+ userQuery: '""',
+ error: 'Cannot have empty string element',
+ },
+];
--- /dev/null
+const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
+
+const PARSED = [
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> F<P>",
+ returned: [{
+ name: "f",
+ fullPath: ["f"],
+ pathWithoutLast: [],
+ pathLast: "f",
+ generics: [
+ {
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ },
+ ],
+ }],
+ typeFilter: -1,
+ userQuery: "-> f<p>",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "-> P",
+ returned: [{
+ name: "p",
+ fullPath: ["p"],
+ pathWithoutLast: [],
+ pathLast: "p",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "-> p",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 1,
+ original: "->,a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "->,a",
+ error: null,
+ },
+ {
+ elems: [{
+ name: "aaaaa",
+ fullPath: ["aaaaa"],
+ pathWithoutLast: [],
+ pathLast: "aaaaa",
+ generics: [],
+ }],
+ foundElems: 2,
+ original: "aaaaa->a",
+ returned: [{
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ }],
+ typeFilter: -1,
+ userQuery: "aaaaa->a",
+ error: null,
+ },
+];
--- /dev/null
+// ignore-tidy-tab
+
+const QUERY = [
+ 'aaaaaa b',
+ 'a b',
+ 'a,b',
+ 'a\tb',
+ 'a<b c>',
+ 'a<b,c>',
+ 'a<b\tc>',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: 'aaaaaa',
+ fullPath: ['aaaaaa'],
+ pathWithoutLast: [],
+ pathLast: 'aaaaaa',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaaaaa b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaaaaa b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a,b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [],
+ },
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a\tb",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a\tb",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b,c>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b,c>",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: 'a',
+ fullPath: ['a'],
+ pathWithoutLast: [],
+ pathLast: 'a',
+ generics: [
+ {
+ name: 'b',
+ fullPath: ['b'],
+ pathWithoutLast: [],
+ pathLast: 'b',
+ generics: [],
+ },
+ {
+ name: 'c',
+ fullPath: ['c'],
+ pathWithoutLast: [],
+ pathLast: 'c',
+ generics: [],
+ },
+ ],
+ },
+ ],
+ foundElems: 1,
+ original: "a<b\tc>",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a<b\tc>",
+ error: null,
+ },
+];
--- /dev/null
+// This test is mostly to check that the parser still kinda outputs something
+// (and doesn't enter an infinite loop!) even though the query is completely
+// invalid.
+const QUERY = [
+ 'a b',
+ 'a b',
+ 'a,b(c)',
+ 'aaa,a',
+ ',,,,',
+ 'mod :',
+ 'mod\t:',
+];
+
+const PARSED = [
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ {
+ name: "b",
+ fullPath: ["b"],
+ pathWithoutLast: [],
+ pathLast: "b",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "a b",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a b",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: "a,b(c)",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "a,b(c)",
+ error: "Unexpected `(`",
+ },
+ {
+ elems: [
+ {
+ name: "aaa",
+ fullPath: ["aaa"],
+ pathWithoutLast: [],
+ pathLast: "aaa",
+ generics: [],
+ },
+ {
+ name: "a",
+ fullPath: ["a"],
+ pathWithoutLast: [],
+ pathLast: "a",
+ generics: [],
+ },
+ ],
+ foundElems: 2,
+ original: "aaa,a",
+ returned: [],
+ typeFilter: -1,
+ userQuery: "aaa,a",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: ",,,,",
+ returned: [],
+ typeFilter: -1,
+ userQuery: ",,,,",
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod :',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod :',
+ error: null,
+ },
+ {
+ elems: [],
+ foundElems: 0,
+ original: 'mod\t:',
+ returned: [],
+ typeFilter: 0,
+ userQuery: 'mod\t:',
+ error: null,
+ },
+];
+// ignore-order
+
const QUERY = '"error"';
+const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
{ 'path': 'std::fmt', 'name': 'Error' },
{ 'path': 'std::io', 'name': 'Error' },
],
- 'in_args': [],
+ 'in_args': [
+ { 'path': 'std::fmt::Error', 'name': 'eq' },
+ { 'path': 'std::fmt::Error', 'name': 'cmp' },
+ { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
+
+ ],
'returned': [
{ 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
],
-const QUERY = 'struct:Vec';
+const QUERY = 'struct:VecD';
const EXPECTED = {
'others': [
- { 'path': 'std::vec', 'name': 'Vec' },
{ 'path': 'std::collections', 'name': 'VecDeque' },
+ { 'path': 'std::vec', 'name': 'Vec' },
],
};
// exact-check
const QUERY = 'macro:print';
+const FILTER_CRATE = 'std';
const EXPECTED = {
'others': [
{ 'path': 'std', 'name': 'println' },
{ 'path': 'std', 'name': 'eprintln' },
{ 'path': 'std::pin', 'name': 'pin' },
- { 'path': 'core::pin', 'name': 'pin' },
+ { 'path': 'std::future', 'name': 'join' },
+ { 'path': 'std', 'name': 'line' },
+ { 'path': 'std', 'name': 'write' },
],
};
'others': [
{ 'path': 'std::vec::Vec', 'name': 'new' },
{ 'path': 'std::vec::Vec', 'name': 'ne' },
- { 'path': 'std::rc::Rc', 'name': 'ne' },
+ { 'path': 'alloc::vec::Vec', 'name': 'ne' },
],
};
// exact-check
-const QUERY = 'true';
+const QUERY = '"true"';
const FILTER_CRATE = 'doc_alias_filter';
const EXPECTED = [
{
+ // StructItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // StructFieldItem
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // StructMethodItem
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // ImplTraitFunction
'others': [
{
'path': 'doc_alias::Struct',
],
},
{
+ // EnumItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // VariantItem
'others': [
{
'path': 'doc_alias::Enum',
],
},
{
+ // EnumMethodItem
'others': [
{
'path': 'doc_alias::Enum',
],
},
{
+ // TypedefItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // TraitItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // TraitTypeItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // AssociatedConstItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // TraitFunctionItem
'others': [
{
'path': 'doc_alias::Trait',
],
},
{
+ // FunctionItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // ModuleItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // ConstItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // StaticItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // UnionItem
'others': [
{
'path': 'doc_alias',
],
},
{
+ // UnionFieldItem
'others': [
{
'path': 'doc_alias::Union',
],
},
{
+ // UnionMethodItem
'others': [
{
'path': 'doc_alias::Union',
],
},
{
+ // MacroItem
'others': [
{
'path': 'doc_alias',
// exact-check
const QUERY = [
- '"R<P>"',
+ 'R<P>',
'"P"',
'P',
- '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ 'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
'TraitCat',
'TraitDog',
+ 'Result<String>',
];
const EXPECTED = [
{
+ // R<P>
'returned': [
{ 'path': 'generics', 'name': 'alef' },
],
],
},
{
+ // "P"
'others': [
{ 'path': 'generics', 'name': 'P' },
],
],
},
{
+ // P
'returned': [
{ 'path': 'generics', 'name': 'alef' },
- { 'path': 'generics', 'name': 'bet' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
- { 'path': 'generics', 'name': 'beta' },
],
},
{
+ // "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
'in_args': [
{ 'path': 'generics', 'name': 'extracreditlabhomework' },
],
'returned': [],
},
{
+ // TraitCat
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
{
+ // TraitDog
'in_args': [
{ 'path': 'generics', 'name': 'gamma' },
],
},
+ {
+ // Result<String>
+ 'others': [],
+ 'returned': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ 'in_args': [
+ { 'path': 'generics', 'name': 'super_soup' },
+ ],
+ },
];
pub trait TraitDog {}
pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
+
+pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
// normalize-stderr-test: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL"
+// check-pass
#![deny(warnings)]
//! Email me at <hello@localhost>.
-//~^ ERROR unknown disambiguator `hello`
//! This should *not* warn: <hello@example.com>.
+++ /dev/null
-error: unknown disambiguator `hello`
- --> $DIR/email-address-localhost.rs:4:18
- |
-LL | //! Email me at <hello@localhost>.
- | ^^^^^
- |
-note: the lint level is defined here
- --> $DIR/email-address-localhost.rs:2:9
- |
-LL | #![deny(warnings)]
- | ^^^^^^^^
- = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]`
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
-
-error: aborting due to previous error
-
--- /dev/null
+// This is a regression for https://github.com/rust-lang/rust/issues/96079.
+
+#![crate_name = "foo"]
+
+pub mod app {
+ pub struct S;
+
+ impl S {
+ // @has 'foo/app/struct.S.html'
+ // @has - '//a[@href="../enums/enum.Foo.html#method.by_name"]' 'Foo::by_name'
+ /**
+ Doc comment hello! [`Foo::by_name`](`crate::enums::Foo::by_name`).
+ */
+ pub fn whatever(&self) {}
+ }
+}
+
+pub mod enums {
+ pub enum Foo {
+ Bar,
+ }
+
+ impl Foo {
+ pub fn by_name(&self) {}
+ }
+}
--- /dev/null
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Simd<T>(_) <br /><span class="where">where<br />    T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre></div>
\ No newline at end of file
--- /dev/null
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait TraitWhere {
+ type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />    <span class="where">where<br />        Self: 'a</span>;
+}</code></pre></div>
\ No newline at end of file
+#![feature(generic_associated_types)]
#![crate_name = "foo"]
pub trait MyTrait { fn dummy(&self) { } }
pub struct Echo<E>(E);
+// @has 'foo/struct.Simd.html'
+// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]'
+pub struct Simd<T>([T; 1])
+where
+ T: MyTrait;
+
+// @has 'foo/trait.TraitWhere.html'
+// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]'
+pub trait TraitWhere {
+ type Item<'a> where Self: 'a;
+}
+
// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
// "impl<E> MyTrait for Echo<E> where E: MyTrait"
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \
//~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
asm!("", in("ip") foo);
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
- asm!("", in("k0") foo);
- //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
asm!("", in("st(2)") foo);
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
asm!("", in("mm0") foo);
//~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+ asm!("", in("k0") foo);
+ //~^ ERROR register class `kreg0` can only be used as a clobber, not as an input or output
asm!("", out("st(2)") _);
asm!("", out("mm0") _);
asm!("{}", in(x87_reg) foo);
LL | asm!("", in("ip") foo);
| ^^^^^^^^^^^^
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
- --> $DIR/bad-reg.rs:32:18
- |
-LL | asm!("", in("k0") foo);
- | ^^^^^^^^^^^^
-
error: register class `x87_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:35:18
+ --> $DIR/bad-reg.rs:33:18
|
LL | asm!("", in("st(2)") foo);
| ^^^^^^^^^^^^^^^
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
- --> $DIR/bad-reg.rs:37:18
+ --> $DIR/bad-reg.rs:35:18
|
LL | asm!("", in("mm0") foo);
| ^^^^^^^^^^^^^
+error: register class `kreg0` can only be used as a clobber, not as an input or output
+ --> $DIR/bad-reg.rs:37:18
+ |
+LL | asm!("", in("k0") foo);
+ | ^^^^^^^^^^^^
+
error: register class `x87_reg` can only be used as a clobber, not as an input or output
--> $DIR/bad-reg.rs:41:20
|
fn main() {
g(issue_67893::run())
- //~^ ERROR generator cannot be sent between threads safely
+ //~^ ERROR future cannot be sent between threads safely
}
-error: generator cannot be sent between threads safely
+error: future cannot be sent between threads safely
--> $DIR/issue-67893.rs:9:7
|
LL | g(issue_67893::run())
- | ^^^^^^^^^^^^^^^^^^ generator is not `Send`
+ | ^^^^^^^^^^^^^^^^^^ future is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+note: future is not `Send` as this value is used across an await
+ --> $DIR/auxiliary/issue_67893.rs:9:26
+ |
+LL | f(*x.lock().unwrap()).await;
+ | ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
+ | |
+ | has type `MutexGuard<'_, ()>` which is not `Send`
+note: `x.lock().unwrap()` is later dropped here
+ --> $DIR/auxiliary/issue_67893.rs:9:32
+ |
+LL | f(*x.lock().unwrap()).await;
+ | ^
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
--> $DIR/issue-87493.rs:8:8
|
LL | T: MyTrait<Assoc == S::Assoc>,
- | ^^^^^^^------------------- help: remove these generics
+ | ^^^^^^^ ----------------- help: replace the generic bound with the associated type: `Assoc = Assoc == S::Assoc`
| |
| expected 0 generic arguments
|
78 00 00 00 ff ff ff ff │ x.......
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error: aborting due to 13 previous errors
78 00 00 00 ff ff ff ff │ x.......
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:92:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-enum.rs:94:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 8, align: 4) {
- 00 00 00 00 00 00 00 00 │ ........
- }
+ | ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
error: aborting due to 13 previous errors
// All variants are uninhabited but also have data.
// Use `0` as constant to make behavior endianess-independent.
const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
-//~^ ERROR is undefined behavior
+//~^ ERROR evaluation of constant value failed
fn main() {
}
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/validate_uninhabited_zsts.rs:16:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
#[warn(const_err)]
const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
-//~^ ERROR it is undefined behavior to use this value
+//~^ ERROR evaluation of constant value failed
//~| WARN the type `Empty` does not permit zero-initialization
fn main() {
//~| HELP remove this lifetime argument
}
+pub trait T {
+ type A;
+ type B;
+}
+
+fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+ //~^ ERROR this trait takes 0 generic arguments
+ //~| HELP replace the generic bounds with the associated types
+}
+
fn main() {}
LL | struct Quux<T>(T);
| ^^^^
-error: aborting due to 9 previous errors
+error[E0107]: this trait takes 0 generic arguments but 2 generic arguments were supplied
+ --> $DIR/E0107.rs:55:27
+ |
+LL | fn trait_bound_generic<I: T<u8, u16>>(_i: I) {
+ | ^ expected 0 generic arguments
+ |
+note: trait defined here, with 0 generic parameters
+ --> $DIR/E0107.rs:50:11
+ |
+LL | pub trait T {
+ | ^
+help: replace the generic bounds with the associated types
+ |
+LL | fn trait_bound_generic<I: T<A = u8, B = u16>>(_i: I) {
+ | ~~~~~~ ~~~~~~~
+
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0107`.
// edition:2021
// run-pass
+// compile-flags: -Zdrop-tracking
#![feature(never_type)]
}
async fn includes_never(crash: bool, x: u32) -> u32 {
- let mut result = async { x * x }.await;
+ let result = async { x * x }.await;
if !crash {
return result;
}
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:36:8
+ --> $DIR/rfc1623.rs:32:8
|
LL | f: &id,
| ^^^ implementation of `FnOnce` is not general enough
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ one type is more general than the other
+LL | f: &id,
+ | ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ one type is more general than the other
+LL | f: &id,
+ | ^^^ one type is more general than the other
|
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
found type `Fn<(&Foo<'_>,)>`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ implementation of `FnOnce` is not general enough
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:29:35
+ --> $DIR/rfc1623.rs:32:8
|
-LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
- | ___________________________________^
-LL | |
-LL | |
-LL | |
-... |
-LL | |
-LL | | };
- | |_^ implementation of `FnOnce` is not general enough
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
|
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
}
static SOME_STRUCT: &SomeStruct = &SomeStruct {
- //[nll]~^ ERROR mismatched types
- //[nll]~| ERROR mismatched types
- //[nll]~| ERROR implementation of `FnOnce` is not general enough
- //[nll]~| ERROR implementation of `FnOnce` is not general enough
foo: &Foo { bools: &[false, true] },
bar: &Bar { bools: &[true, true] },
f: &id,
//[base]~^ ERROR implementation of `FnOnce` is not general enough
+ //[nll]~^^ ERROR mismatched types
+ //[nll]~| ERROR mismatched types
+ //[nll]~| ERROR implementation of `FnOnce` is not general enough
+ //[nll]~| ERROR implementation of `FnOnce` is not general enough
};
// very simple test for a 'static static with default lifetime
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
+ |
+LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | ---- ---- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:82
+ |
+LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ---- ----------------- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
+ |
+LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | ------ --- ^^^ ...but data from `arg` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:52
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:75
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:15:75
|
LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:22:64
|
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| -- - ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
use std::pin::Pin;
impl Foo {
async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- //~^ ERROR lifetime mismatch
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ lifetime may not live long enough
async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- //~^ ERROR lifetime mismatch
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ lifetime may not live long enough
}
type Alias<T> = Pin<T>;
impl Foo {
- async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+ async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
- |
-LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- | ---- ---- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
- |
-LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ---- ----------------- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
- |
-LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
- | ------ --- ^^^ ...but data from `arg` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
+ |
+LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | ---- ---- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:76
+ |
+LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ---- ----------------- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
+ |
+LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | ------ --- ^^^ ...but data from `arg` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:46
|
LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| - - ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:69
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:69
|
LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
| - - ^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
| let's call the lifetime of this reference `'2`
error: lifetime may not live long enough
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:58
|
LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| -- ---- has type `Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
use std::pin::Pin;
struct Foo;
impl Foo {
- fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+ fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
- fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+ fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
type Alias<T> = Pin<T>;
impl Foo {
- fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+ fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ //[base]~^ ERROR E0623
+ //[nll]~^^ lifetime may not live long enough
}
fn main() {}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
- |
-LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
- | ---- ---- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:76
- |
-LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ---- ----------------- ^ ...but data from `f` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58
- |
-LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
- | ------ --- ^^^ ...but data from `arg` is returned here
- | |
- | this parameter and the return type are declared with different lifetimes...
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:16:9
+ |
+LL | async fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:24:9
+ |
+LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:30:9
+ |
+LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:36:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:42:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self-async.rs:48:9
+ |
+LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:13:9
+ --> $DIR/lt-ref-self-async.rs:16:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:19:9
+ --> $DIR/lt-ref-self-async.rs:24:9
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:23:9
+ --> $DIR/lt-ref-self-async.rs:30:9
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:27:9
+ --> $DIR/lt-ref-self-async.rs:36:9
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:31:9
+ --> $DIR/lt-ref-self-async.rs:42:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self-async.rs:35:9
+ --> $DIR/lt-ref-self-async.rs:48:9
|
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&self` sugar:
async fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:13:9
- |
-LL | async fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:19:9
- |
-LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:23:9
- |
-LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:27:9
- |
-LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:31:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self-async.rs:35:9
- |
-LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:15:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:23:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:29:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:41:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:47:9
+ |
+LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:11:9
+ --> $DIR/lt-ref-self.rs:15:9
|
LL | fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:17:9
+ --> $DIR/lt-ref-self.rs:23:9
|
LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:21:9
+ --> $DIR/lt-ref-self.rs:29:9
|
LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:25:9
+ --> $DIR/lt-ref-self.rs:35:9
|
LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:29:9
+ --> $DIR/lt-ref-self.rs:41:9
|
LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/lt-ref-self.rs:33:9
+ --> $DIR/lt-ref-self.rs:47:9
|
LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&self` sugar:
fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:11:9
- |
-LL | fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:17:9
- |
-LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:21:9
- |
-LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:25:9
- |
-LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:29:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/lt-ref-self.rs:33:9
- |
-LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:16:9
+ |
+LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:24:9
+ |
+LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:30:9
+ |
+LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:36:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:42:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self-async.rs:48:9
+ |
+LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:13:9
+ --> $DIR/ref-mut-self-async.rs:16:9
|
LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:19:9
+ --> $DIR/ref-mut-self-async.rs:24:9
|
LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:23:9
+ --> $DIR/ref-mut-self-async.rs:30:9
|
LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:27:9
+ --> $DIR/ref-mut-self-async.rs:36:9
|
LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:31:9
+ --> $DIR/ref-mut-self-async.rs:42:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self-async.rs:35:9
+ --> $DIR/ref-mut-self-async.rs:48:9
|
LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&mut self` sugar:
async fn ref_self(&mut self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&mut Self` explicitly:
async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:13:9
- |
-LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:19:9
- |
-LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:23:9
- |
-LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:27:9
- |
-LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:31:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self-async.rs:35:9
- |
-LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:15:9
+ |
+LL | fn ref_self(&mut self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:23:9
+ |
+LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:29:9
+ |
+LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:41:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:47:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:11:9
+ --> $DIR/ref-mut-self.rs:15:9
|
LL | fn ref_self(&mut self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:17:9
+ --> $DIR/ref-mut-self.rs:23:9
|
LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:21:9
+ --> $DIR/ref-mut-self.rs:29:9
|
LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:25:9
+ --> $DIR/ref-mut-self.rs:35:9
|
LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:29:9
+ --> $DIR/ref-mut-self.rs:41:9
|
LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-self.rs:33:9
+ --> $DIR/ref-mut-self.rs:47:9
|
LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&mut self` sugar:
fn ref_self(&mut self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&mut Self` explicitly:
fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:11:9
- |
-LL | fn ref_self(&mut self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:17:9
- |
-LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:21:9
- |
-LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:25:9
- |
-LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:29:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-self.rs:33:9
- |
-LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:16:9
+ |
+LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:22:9
+ |
+LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:28:9
+ |
+LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:34:9
+ |
+LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct-async.rs:40:9
+ |
+LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:13:9
+ --> $DIR/ref-mut-struct-async.rs:16:9
|
LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:17:9
+ --> $DIR/ref-mut-struct-async.rs:22:9
|
LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:21:9
+ --> $DIR/ref-mut-struct-async.rs:28:9
|
LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:25:9
+ --> $DIR/ref-mut-struct-async.rs:34:9
|
LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct-async.rs:29:9
+ --> $DIR/ref-mut-struct-async.rs:40:9
|
LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&mut Struct` explicitly:
async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:13:9
- |
-LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:17:9
- |
-LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:21:9
- |
-LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:25:9
- |
-LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct-async.rs:29:9
- |
-LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:15:9
+ |
+LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:21:9
+ |
+LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:27:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:33:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:39:9
+ |
+LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:11:9
+ --> $DIR/ref-mut-struct.rs:15:9
|
LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:15:9
+ --> $DIR/ref-mut-struct.rs:21:9
|
LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:19:9
+ --> $DIR/ref-mut-struct.rs:27:9
|
LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:23:9
+ --> $DIR/ref-mut-struct.rs:33:9
|
LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-mut-struct.rs:27:9
+ --> $DIR/ref-mut-struct.rs:39:9
|
LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&mut Struct` explicitly:
fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:11:9
- |
-LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:15:9
- |
-LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:19:9
- |
-LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:23:9
- |
-LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-mut-struct.rs:27:9
- |
-LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:26:9
+ |
+LL | async fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:34:9
+ |
+LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:40:9
+ |
+LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:46:9
+ |
+LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:52:9
+ |
+LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:58:9
+ |
+LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self-async.rs:64:9
+ |
+LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | --- ---
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:23:9
+ --> $DIR/ref-self-async.rs:26:9
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:29:9
+ --> $DIR/ref-self-async.rs:34:9
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:33:9
+ --> $DIR/ref-self-async.rs:40:9
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:37:9
+ --> $DIR/ref-self-async.rs:46:9
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:41:9
+ --> $DIR/ref-self-async.rs:52:9
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:45:9
+ --> $DIR/ref-self-async.rs:58:9
|
LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self-async.rs:49:9
+ --> $DIR/ref-self-async.rs:64:9
|
LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
#![feature(arbitrary_self_types)]
// Test using `&self` sugar:
async fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:23:9
- |
-LL | async fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:29:9
- |
-LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:33:9
- |
-LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:37:9
- |
-LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:41:9
- |
-LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:45:9
- |
-LL | async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self-async.rs:49:9
- |
-LL | async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- | --- ---
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:25:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:33:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:39:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:45:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:51:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:57:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:63:9
+ |
+LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | --- ---
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
+ | ++++ ++ ++
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:21:9
+ --> $DIR/ref-self.rs:25:9
|
LL | fn ref_self(&self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:27:9
+ --> $DIR/ref-self.rs:33:9
|
LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:31:9
+ --> $DIR/ref-self.rs:39:9
|
LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:35:9
+ --> $DIR/ref-self.rs:45:9
|
LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:39:9
+ --> $DIR/ref-self.rs:51:9
|
LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:43:9
+ --> $DIR/ref-self.rs:57:9
|
LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-self.rs:47:9
+ --> $DIR/ref-self.rs:63:9
|
LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![feature(arbitrary_self_types)]
#![allow(non_snake_case)]
// Test using `&self` sugar:
fn ref_self(&self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
// Test using `&Self` explicitly:
fn ref_Self(self: &Self, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:21:9
- |
-LL | fn ref_self(&self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:27:9
- |
-LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:31:9
- |
-LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:35:9
- |
-LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:39:9
- |
-LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:43:9
- |
-LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-self.rs:47:9
- |
-LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
- | --- ---
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
- | ++++ ++ ++
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:16:9
+ |
+LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:22:9
+ |
+LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:28:9
+ |
+LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:34:9
+ |
+LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct-async.rs:40:9
+ |
+LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:13:9
+ --> $DIR/ref-struct-async.rs:16:9
|
LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:17:9
+ --> $DIR/ref-struct-async.rs:22:9
|
LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:21:9
+ --> $DIR/ref-struct-async.rs:28:9
|
LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:25:9
+ --> $DIR/ref-struct-async.rs:34:9
|
LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct-async.rs:29:9
+ --> $DIR/ref-struct-async.rs:40:9
|
LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
// edition:2018
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
#![allow(non_snake_case)]
// Test using `&Struct` explicitly:
async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:13:9
- |
-LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:17:9
- |
-LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:21:9
- |
-LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:25:9
- |
-LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct-async.rs:29:9
- |
-LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:15:9
+ |
+LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:21:9
+ |
+LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:27:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:33:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:39:9
+ |
+LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter and update trait if needed
+ |
+LL | fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
+ | ++++ ++ ++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:11:9
+ --> $DIR/ref-struct.rs:15:9
|
LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:15:9
+ --> $DIR/ref-struct.rs:21:9
|
LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:19:9
+ --> $DIR/ref-struct.rs:27:9
|
LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:23:9
+ --> $DIR/ref-struct.rs:33:9
|
LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
| ^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: lifetime may not live long enough
- --> $DIR/ref-struct.rs:27:9
+ --> $DIR/ref-struct.rs:39:9
|
LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
| - - let's call the lifetime of this reference `'1`
+// revisions: base nll
+// ignore-compare-mode-nll
+//[nll] compile-flags: -Z borrowck=mir
+
#![allow(non_snake_case)]
use std::pin::Pin;
// Test using `&Struct` explicitly:
fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- f //~ ERROR lifetime mismatch
+ f
+ //[base]~^ ERROR lifetime mismatch
+ //[nll]~^^ ERROR lifetime may not live long enough
}
}
+++ /dev/null
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:11:9
- |
-LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:15:9
- |
-LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:19:9
- |
-LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:23:9
- |
-LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error[E0623]: lifetime mismatch
- --> $DIR/ref-struct.rs:27:9
- |
-LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
- | ---- ----
- | |
- | this parameter and the return type are declared with different lifetimes...
-LL | f
- | ^ ...but data from `f` is returned here
- |
- = note: each elided lifetime in input position becomes a distinct lifetime
-help: consider introducing a named lifetime parameter and update trait if needed
- |
-LL | fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
- | ++++ ++ ++
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0623`.
static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
-//~| ERROR undefined behavior to use this value
+//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization
fn main() {}
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/uninhabited-static.rs:12:1
+error[E0080]: could not evaluate static initializer
+ --> $DIR/uninhabited-static.rs:12:31
|
LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/uninhabited-static.rs:16:1
+error[E0080]: could not evaluate static initializer
+ --> $DIR/uninhabited-static.rs:16:32
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
- = note: the raw bytes of the constant (size: 0, align: 1) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type
warning: the type `Void` does not permit zero-initialization
--> $DIR/uninhabited-static.rs:12:31
--- /dev/null
+use std::ops::Deref;
+
+struct Foo {
+ v: Vec<u32>,
+}
+
+struct Bar {
+ v: Vec<u32>,
+}
+
+impl Deref for Bar {
+ type Target = Vec<u32>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.v
+ }
+}
+
+fn f(foo: &Foo) {
+ match foo {
+ Foo { v: [1, 2] } => {}
+ //~^ ERROR expected an array or slice, found `Vec<u32>
+ _ => {}
+ }
+}
+
+fn bar(bar: &Bar) {
+ match bar {
+ Bar { v: [1, 2] } => {}
+ //~^ ERROR expected an array or slice, found `Vec<u32>
+ _ => {}
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0529]: expected an array or slice, found `Vec<u32>`
+ --> $DIR/pattern-struct-with-slice-vec-field.rs:21:18
+ |
+LL | Foo { v: [1, 2] } => {}
+ | ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error[E0529]: expected an array or slice, found `Vec<u32>`
+ --> $DIR/pattern-struct-with-slice-vec-field.rs:29:18
+ |
+LL | Bar { v: [1, 2] } => {}
+ | ^^^^^^ pattern cannot match with input type `Vec<u32>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0529`.
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
|
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
- | ^ ------------ help: remove these generic arguments
- | |
- | expected 2 generic arguments
+ | ^ expected 2 generic arguments
|
note: trait defined here, with 2 generic parameters: `X`, `Y`
--> $DIR/use-type-argument-instead-of-assoc-type.rs:1:11
|
LL | pub trait T<X, Y> {
| ^ - -
+help: replace the generic bounds with the associated types
+ |
+LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
+ | ~~~~~~~~~ ~~~~~~~~~
error[E0191]: the value of the associated types `A` (from trait `T`), `C` (from trait `T`) must be specified
--> $DIR/use-type-argument-instead-of-assoc-type.rs:7:16
...
LL | i: Box<dyn T<usize, usize, usize, usize, B=usize>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated types `A`, `C` must be specified
- |
-help: specify the associated types
- |
-LL | i: Box<dyn T<usize, usize, A = usize, C = usize, B=usize>>,
- | ~~~~~~~~~ ~~~~~~~~~
error: aborting due to 2 previous errors
--- /dev/null
+// Verifies that MIR building for a call expression respects
+// privacy when checking if a call return type is uninhabited.
+
+pub mod widget {
+ enum Unimplemented {}
+ pub struct Widget(Unimplemented);
+
+ impl Widget {
+ pub fn new() -> Widget {
+ todo!();
+ }
+ }
+
+ pub fn f() {
+ let x: &mut u32;
+ Widget::new();
+ // Ok. Widget type returned from new is known to be uninhabited
+ // and the following code is considered unreachable.
+ *x = 1;
+ }
+}
+
+fn main() {
+ let y: &mut u32;
+ widget::Widget::new();
+ // Error. Widget type is not known to be uninhabited here,
+ // so the following code is considered reachable.
+ *y = 2; //~ ERROR use of possibly-uninitialized variable
+}
--- /dev/null
+error[E0381]: use of possibly-uninitialized variable: `y`
+ --> $DIR/privately-uninhabited-mir-call.rs:28:5
+ |
+LL | *y = 2;
+ | ^^^^^^ use of possibly-uninitialized `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+ --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
|
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+ |
+LL | *a = 1;
+ | ^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+ |
+LL | *b = 1;
+ | ^^^^^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0133`.
+// Verify that unreachable code undergoes unsafety checks.
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
*(1 as *mut u32) = 42;
//~^ ERROR dereference of raw pointer is unsafe
}
+
+fn panic() -> ! {
+ panic!();
+}
+
+fn f(a: *mut u32) {
+ panic();
+ *a = 1;
+ //~^ ERROR dereference of raw pointer is unsafe
+}
+
+enum Void {}
+
+fn uninhabited() -> Void {
+ panic!();
+}
+
+fn g(b: *mut u32) {
+ uninhabited();
+ *b = 1;
+ //~^ ERROR dereference of raw pointer is unsafe
+}
error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
- --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+ --> $DIR/issue-45087-unreachable-unsafe.rs:7:5
|
LL | *(1 as *mut u32) = 42;
| ^^^^^^^^^^^^^^^^ dereference of raw pointer
|
= note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
-error: aborting due to previous error
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:17:5
+ |
+LL | *a = 1;
+ | ^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+ --> $DIR/issue-45087-unreachable-unsafe.rs:29:5
+ |
+LL | *b = 1;
+ | ^^ dereference of raw pointer
+ |
+ = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// --extern-location with bad location type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=badloc:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: unknown location type `badloc`: use `raw` or `json`
-
+++ /dev/null
-// Default extern location from name and path if one isn't specified
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--error-format json
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":146,"byte_end":146,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-defl-json.rs","byte_start":154,"byte_end":179,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"name":"bar"}}],"rendered":"warning: external crate `bar` unused in `extern_loc_defl_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-defl-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-defl-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:[{"malformed -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: malformed json location `[{"malformed`
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":189,"byte_end":189,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-json-json.rs","byte_start":197,"byte_end":222,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":{"key":123,"value":{}}}],"rendered":"warning: external crate `bar` unused in `extern_loc_json_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-json-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-json-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=json:{"key":123,"value":{}} -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-warning: external crate `bar` unused in `extern_loc_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
-
-warning: 1 warning emitted
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar -Zunstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: specify location for extern crate `bar`
-
+++ /dev/null
-// --extern-location with no type
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=missing-loc-type -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: unknown location type `missing-loc-type`: use `raw` or `json`
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file --error-format json -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-{"message":"external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`","code":{"code":"unused_crate_dependencies","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":182,"byte_end":182,"line_start":7,"line_end":7,"column_start":1,"column_end":1,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":1,"highlight_end":1}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"the lint level is defined here","code":null,"level":"note","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":190,"byte_end":215,"line_start":7,"line_end":7,"column_start":9,"column_end":34,"is_primary":true,"text":[{"text":"#![warn(unused_crate_dependencies)]","highlight_start":9,"highlight_end":34}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":null},{"message":"remove unnecessary dependency `bar` at `in-the-test-file`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"raw extern location","code":null,"level":"help","spans":[{"file_name":"$DIR/extern-loc-raw-json.rs","byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1,"is_primary":true,"text":[],"label":null,"suggested_replacement":"in-the-test-file","suggestion_applicability":"Unspecified","expansion":null}],"children":[],"rendered":null},{"message":"json extern location","code":null,"level":"help","spans":[],"children":[],"rendered":null,"tool_metadata":"in-the-test-file"}],"rendered":"warning: external crate `bar` unused in `extern_loc_raw_json`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-raw-json.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-raw-json.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-"}
-{"message":"1 warning emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"warning: 1 warning emitted
-
-"}
+++ /dev/null
-// --extern-location with a raw reference
-
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-
-fn main() {}
+++ /dev/null
-error: `--extern-location`: missing `raw` location
-
+++ /dev/null
-// --extern-location with a raw reference
-
-// check-pass
-// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar=raw:in-the-test-file -Z unstable-options
-
-#![warn(unused_crate_dependencies)]
-//~^ WARNING external crate `bar` unused in
-
-fn main() {}
+++ /dev/null
-warning: external crate `bar` unused in `extern_loc_raw`: remove the dependency or add `use bar as _;`
- --> $DIR/extern-loc-raw.rs:7:1
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^
- |
-note: the lint level is defined here
- --> $DIR/extern-loc-raw.rs:7:9
- |
-LL | #![warn(unused_crate_dependencies)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar` at `in-the-test-file`
-
-warning: 1 warning emitted
-
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `barbar`
warning: 1 warning emitted
|
LL | #![warn(unused_crate_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
| ^
|
= note: requested on the command line with `-W unused-crate-dependencies`
- = help: remove unnecessary dependency `bar`
warning: 1 warning emitted
-Subproject commit dba5baf4345858c591517b24801902a062c399f8
+Subproject commit edffc4ada3d77799e5a04eeafd9b2f843d29fc23
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, DefIdTree};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Span;
hir::ItemKind::Fn(..) => {
// ignore main()
if it.ident.name == sym::main {
- let def_key = cx.tcx.hir().def_key(it.def_id);
- if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
+ let at_root = cx.tcx.local_parent(it.def_id) == Some(CRATE_DEF_ID);
+ if at_root {
return;
}
}
-Subproject commit 1ef91e122775060acb1fbda2c9a366891af3ea89
+Subproject commit edd4858846003dc96020a0de07a1499e3224e633
} while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
// Eat quoted strings
- } else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
+ } else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
+ (pos === 0 || content[pos - 1] !== '/')) {
stop = content[pos];
do {
if (content[pos] === '\\') {
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
- "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
- "removeEmptyStringsFromArray"];
+ "buildIndex", "execQuery", "parseQuery", "createQueryResults",
+ "isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
+ "parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
+ "isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
+ "itemTypeFromName", "isEndCharacter", "isErrorCharacter",
+ "isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
+ "checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
const functions = ["hasOwnPropertyRustdoc", "onEach"];
ALIASES = {};
return [loaded, index];
}
+// This function checks if `expected` has all the required fields needed for the checks.
+function checkNeededFields(fullPath, expected, error_text, queryName, position) {
+ let fieldsToCheck;
+ if (fullPath.length === 0) {
+ fieldsToCheck = [
+ "foundElems",
+ "original",
+ "returned",
+ "typeFilter",
+ "userQuery",
+ "error",
+ ];
+ } else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
+ fieldsToCheck = [
+ "name",
+ "fullPath",
+ "pathWithoutLast",
+ "pathLast",
+ "generics",
+ ];
+ } else {
+ fieldsToCheck = [];
+ }
+ for (var i = 0; i < fieldsToCheck.length; ++i) {
+ const field = fieldsToCheck[i];
+ if (!expected.hasOwnProperty(field)) {
+ let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
+ if (fullPath.length > 0) {
+ text += ` in field \`${fullPath}\``;
+ if (position != null) {
+ text += ` (position ${position})`;
+ }
+ }
+ error_text.push(text);
+ }
+ }
+}
+
+function valueCheck(fullPath, expected, result, error_text, queryName) {
+ if (Array.isArray(expected)) {
+ for (var i = 0; i < expected.length; ++i) {
+ checkNeededFields(fullPath, expected[i], error_text, queryName, i);
+ if (i >= result.length) {
+ error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
+ `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
+ } else {
+ valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
+ }
+ }
+ for (; i < result.length; ++i) {
+ error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
+ `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
+ 'compared to EXPECTED');
+ }
+ } else if (expected !== null && typeof expected !== "undefined" &&
+ expected.constructor == Object)
+ {
+ for (const key in expected) {
+ if (!expected.hasOwnProperty(key)) {
+ continue;
+ }
+ if (!result.hasOwnProperty(key)) {
+ error_text.push('==> Unknown key "' + key + '"');
+ break;
+ }
+ const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
+ valueCheck(obj_path, expected[key], result[key], error_text, queryName);
+ }
+ } else {
+ expectedValue = JSON.stringify(expected);
+ resultValue = JSON.stringify(result);
+ if (expectedValue != resultValue) {
+ error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
+ `EXPECTED: \`${expectedValue}\`\nRESULT: \`${resultValue}\``);
+ }
+ }
+}
+
+function runParser(query, expected, loaded, loadedFile, queryName) {
+ var error_text = [];
+ checkNeededFields("", expected, error_text, queryName, null);
+ if (error_text.length === 0) {
+ valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
+ }
+ return error_text;
+}
+
function runSearch(query, expected, index, loaded, loadedFile, queryName) {
const filter_crate = loadedFile.FILTER_CRATE;
const ignore_order = loadedFile.ignore_order;
const exact_check = loadedFile.exact_check;
- var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
+ var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
var error_text = [];
for (var key in expected) {
return 1;
}
-function runChecks(testFile, loaded, index) {
- var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
- if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
- testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
- } else {
- testFileContent += "exports.FILTER_CRATE = null;";
- }
- var loadedFile = loadContent(testFileContent);
-
- const expected = loadedFile.EXPECTED;
+function runCheck(loadedFile, key, callback) {
+ const expected = loadedFile[key];
const query = loadedFile.QUERY;
if (Array.isArray(query)) {
if (!Array.isArray(expected)) {
console.log("FAILED");
- console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
+ console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
return 1;
} else if (query.length !== expected.length) {
console.log("FAILED");
- console.log("==> QUERY variable should have the same length as EXPECTED");
+ console.log(`==> QUERY variable should have the same length as ${key}`);
return 1;
}
for (var i = 0; i < query.length; ++i) {
- var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
- "[ query `" + query[i] + "`]");
+ var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
if (checkResult(error_text, loadedFile, false) !== 0) {
return 1;
}
}
console.log("OK");
- return 0;
+ } else {
+ var error_text = callback(query, expected, "");
+ if (checkResult(error_text, loadedFile, true) !== 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+function runChecks(testFile, loaded, index) {
+ var checkExpected = false;
+ var checkParsed = false;
+ var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
+
+ if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
+ testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+ } else {
+ testFileContent += "exports.FILTER_CRATE = null;";
+ }
+
+ if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
+ testFileContent += 'exports.EXPECTED = EXPECTED;';
+ checkExpected = true;
+ }
+ if (testFileContent.indexOf("\nconst PARSED") !== -1) {
+ testFileContent += 'exports.PARSED = PARSED;';
+ checkParsed = true;
+ }
+ if (!checkParsed && !checkExpected) {
+ console.log("FAILED");
+ console.log("==> At least `PARSED` or `EXPECTED` is needed!");
+ return 1;
+ }
+
+ const loadedFile = loadContent(testFileContent);
+ var res = 0;
+
+ if (checkExpected) {
+ res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
+ return runSearch(query, expected, index, loaded, loadedFile, text);
+ });
+ }
+ if (checkParsed) {
+ res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
+ return runParser(query, expected, loaded, loadedFile, text);
+ });
}
- var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
- return checkResult(error_text, loadedFile, true);
+ return res;
}
function load_files(doc_folder, resource_suffix, crate) {
("self_cell", "Apache-2.0"), // rustc (fluent translations)
// FIXME: this dependency violates the documentation comment above:
("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
+ ("dunce", "CC0-1.0"), // cargo (dev dependency)
+ ("similar", "Apache-2.0"), // cargo (dev dependency)
+ ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency)
];
const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[