-name: Internal Compiler Error (Structured form)
+name: Internal Compiler Error (for use by automated tooling)
description: For now, you'll want to use the other ICE template, as GitHub forms have strict limits on the size of fields so backtraces cannot be pasted directly.
labels: ["C-bug", "I-ICE", "T-compiler"]
title: "[ICE]: "
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
[[package]]
name = "arrayvec"
version = "0.7.0"
"unicode-xid",
"url",
"walkdir",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
version = "0.2.0"
dependencies = [
"cargo-credential",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
"time 0.3.17",
"toml_edit",
"url",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
"shell-escape",
"tempfile",
"walkdir",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
name = "clippy_utils"
version = "0.1.69"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
"if_chain",
"itertools",
"rustc-semver",
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"libc",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"hermit-abi 0.2.6",
"io-lifetimes",
"rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
dependencies = [
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"libc",
"redox_syscall",
"smallvec",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
name = "rustc_data_structures"
version = "0.0.0"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
"bitflags",
"cfg-if",
"ena",
name = "rustc_index"
version = "0.0.0"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
"rustc_macros",
"rustc_serialize",
"smallvec",
name = "rustdoc"
version = "0.0.0"
dependencies = [
- "arrayvec",
+ "arrayvec 0.7.0",
"askama",
"expect-test",
"itertools",
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
[[package]]
name = "strip-ansi-escapes"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d63676e2abafa709460982ddc02a3bb586b6d15a49b75c212e06edd3933acee"
+checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
dependencies = [
"vte",
]
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
[[package]]
name = "utf8parse"
-version = "0.1.1"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d"
+checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
[[package]]
name = "uuid"
[[package]]
name = "vte"
-version = "0.3.3"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
+checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
dependencies = [
+ "arrayvec 0.5.2",
"utf8parse",
+ "vte_generate_state_changes",
+]
+
+[[package]]
+name = "vte_generate_state_changes"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
]
[[package]]
"windows_x86_64_msvc",
]
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "writeable"
match bound {
GenericBound::Trait(tref, modifier) => {
- if modifier == &TraitBoundModifier::Maybe {
- self.word("?");
+ match modifier {
+ TraitBoundModifier::None => {}
+ TraitBoundModifier::Maybe => {
+ self.word("?");
+ }
+ TraitBoundModifier::MaybeConst => {
+ self.word_space("~const");
+ }
+ TraitBoundModifier::MaybeConstMaybe => {
+ self.word_space("~const");
+ self.word("?");
+ }
}
self.print_poly_trait_ref(tref);
}
if let ty::Adt(def, substs) = ty.kind()
&& Some(def.did()) == tcx.lang_items().pin_type()
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
- && let self_ty = infcx.replace_bound_vars_with_fresh_vars(
+ && let self_ty = infcx.instantiate_binder_with_fresh_vars(
fn_call_span,
LateBoundRegionConversionTime::FnCall,
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
}
self.constraints.member_constraints = tmp;
- for (predicate, constraint_category) in outlives {
- // At the moment, we never generate any "higher-ranked"
- // region constraints like `for<'a> 'a: 'b`. At some point
- // when we move to universes, we will, and this assertion
- // will start to fail.
- let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", predicate,);
- });
-
- self.convert(predicate, *constraint_category);
+ for &(predicate, constraint_category) in outlives {
+ self.convert(predicate, constraint_category);
}
}
// so that they represent the view from "inside" the closure.
let user_provided_sig = self
.instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
- let user_provided_sig = self.infcx.replace_bound_vars_with_fresh_vars(
+ let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
body.span,
LateBoundRegionConversionTime::FnCall,
user_provided_sig,
let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug]));
let ty_dyn_debug = cx.ty(
span,
- ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn),
+ ast::TyKind::TraitObject(
+ vec![cx.trait_bound(path_debug, false)],
+ ast::TraitObjectSyntax::Dyn,
+ ),
);
let ty_slice = cx.ty(
span,
let bounds: Vec<_> = self
.additional_bounds
.iter()
- .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+ .map(|p| {
+ cx.trait_bound(
+ p.to_path(cx, self.span, type_ident, generics),
+ self.is_const,
+ )
+ })
.chain(
// Add a bound for the current trait.
self.skip_path_as_bound
.not()
- .then(|| cx.trait_bound(trait_path.clone())),
+ .then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
)
.chain({
// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
let p = deriving::path_std!(marker::Copy);
- Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+ Some(cx.trait_bound(
+ p.to_path(cx, self.span, type_ident, generics),
+ self.is_const,
+ ))
} else {
None
}
let mut bounds: Vec<_> = self
.additional_bounds
.iter()
- .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+ .map(|p| {
+ cx.trait_bound(
+ p.to_path(cx, self.span, type_ident, generics),
+ self.is_const,
+ )
+ })
.collect();
// Require the current trait.
- bounds.push(cx.trait_bound(trait_path.clone()));
+ bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
let p = deriving::path_std!(marker::Copy);
- bounds.push(
- cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
- );
+ bounds.push(cx.trait_bound(
+ p.to_path(cx, self.span, type_ident, generics),
+ self.is_const,
+ ));
}
let predicate = ast::WhereBoundPredicate {
}),
),
);
- // In general, fields in packed structs are copied via a
- // block, e.g. `&{self.0}`. The one exception is `[u8]`
- // fields, which cannot be copied and also never cause
- // unaligned references. This exception is allowed to
- // handle the `FlexZeroSlice` type in the `zerovec` crate
- // within `icu4x-0.9.0`.
- //
- // Once use of `icu4x-0.9.0` has dropped sufficiently, this
- // exception should be removed.
- let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
- let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind &&
- let [seg] = segments.as_slice() &&
- seg.ident.name == sym::u8 && seg.args.is_none()
- {
- true
- } else {
- false
- };
if is_packed {
- if is_u8_slice {
+ // In general, fields in packed structs are copied via a
+ // block, e.g. `&{self.0}`. The two exceptions are `[u8]`
+ // and `str` fields, which cannot be copied and also never
+ // cause unaligned references. These exceptions are allowed
+ // to handle the `FlexZeroSlice` type in the `zerovec`
+ // crate within `icu4x-0.9.0`.
+ //
+ // Once use of `icu4x-0.9.0` has dropped sufficiently, this
+ // exception should be removed.
+ let is_simple_path = |ty: &P<ast::Ty>, sym| {
+ if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind &&
+ let [seg] = segments.as_slice() &&
+ seg.ident.name == sym && seg.args.is_none()
+ {
+ true
+ } else {
+ false
+ }
+ };
+
+ let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
+ is_simple_path(ty, sym::u8)
+ {
+ Some("byte")
+ } else if is_simple_path(&struct_field.ty, sym::str) {
+ Some("string")
+ } else {
+ None
+ };
+
+ if let Some(ty) = exception {
cx.sess.parse_sess.buffer_lint_with_diagnostic(
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
sp,
ast::CRATE_NODE_ID,
- "byte slice in a packed struct that derives a built-in trait",
+ &format!(
+ "{} slice in a packed struct that derives a built-in trait",
+ ty
+ ),
rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
);
} else {
.iter()
.map(|b| {
let path = b.to_path(cx, span, self_ident, self_generics);
- cx.trait_bound(path)
+ cx.trait_bound(path, false)
})
.collect();
cx.typaram(span, Ident::new(name, span), bounds, None)
let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?;
let vtable = Scalar::from_maybe_pointer(vtable, self);
let data = self.read_immediate(src)?.to_scalar();
- let _assert_pointer_sized = data.to_pointer(self)?;
+ let _assert_pointer_like = data.to_pointer(self)?;
let val = Immediate::ScalarPair(data, vtable);
self.write_immediate(val, dest)?;
} else {
col: u32,
) -> MPlaceTy<'tcx, M::Provenance> {
let loc_details = &self.tcx.sess.opts.unstable_opts.location_detail;
+ // This can fail if rustc runs out of memory right here. Trying to emit an error would be
+ // pointless, since that would require allocating more memory than these short strings.
let file = if loc_details.file {
self.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ .unwrap()
} else {
// FIXME: This creates a new allocation each time. It might be preferable to
// perform this allocation only once, and re-use the `MPlaceTy`.
// See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
- self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap()
};
let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
.bound_type_of(self.tcx.require_lang_item(LangItem::PanicLocation, None))
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_erased.into()].iter()));
let loc_layout = self.layout_of(loc_ty).unwrap();
- // This can fail if rustc runs out of memory right here. Trying to emit an error would be
- // pointless, since that would require allocating more memory than a Location.
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.
fn adjust_alloc_base_pointer(
ecx: &InterpCx<'mir, 'tcx, Self>,
ptr: Pointer,
- ) -> Pointer<Self::Provenance>;
+ ) -> InterpResult<'tcx, Pointer<Self::Provenance>>;
/// "Int-to-pointer cast"
fn ptr_from_addr_cast(
fn adjust_alloc_base_pointer(
_ecx: &InterpCx<$mir, $tcx, Self>,
ptr: Pointer<AllocId>,
- ) -> Pointer<AllocId> {
- ptr
+ ) -> InterpResult<$tcx, Pointer<AllocId>> {
+ Ok(ptr)
}
#[inline(always)]
_ => {}
}
// And we need to get the provenance.
- Ok(M::adjust_alloc_base_pointer(self, ptr))
+ M::adjust_alloc_base_pointer(self, ptr)
}
pub fn create_fn_alloc_ptr(
kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
let alloc = Allocation::uninit(size, align, M::PANIC_ON_ALLOC_FAIL)?;
- // We can `unwrap` since `alloc` contains no pointers.
- Ok(self.allocate_raw_ptr(alloc, kind).unwrap())
+ self.allocate_raw_ptr(alloc, kind)
}
pub fn allocate_bytes_ptr(
align: Align,
kind: MemoryKind<M::MemoryKind>,
mutability: Mutability,
- ) -> Pointer<M::Provenance> {
+ ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
let alloc = Allocation::from_bytes(bytes, align, mutability);
- // We can `unwrap` since `alloc` contains no pointers.
- self.allocate_raw_ptr(alloc, kind).unwrap()
+ self.allocate_raw_ptr(alloc, kind)
}
/// This can fail only of `alloc` contains provenance.
);
let alloc = M::adjust_allocation(self, id, Cow::Owned(alloc), Some(kind))?;
self.memory.alloc_map.insert(id, (kind, alloc.into_owned()));
- Ok(M::adjust_alloc_base_pointer(self, Pointer::from(id)))
+ M::adjust_alloc_base_pointer(self, Pointer::from(id))
}
pub fn reallocate_ptr(
str: &str,
kind: MemoryKind<M::MemoryKind>,
mutbl: Mutability,
- ) -> MPlaceTy<'tcx, M::Provenance> {
- let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
+ ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
+ let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?;
let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
);
let layout = self.layout_of(ty).unwrap();
- MPlaceTy { mplace, layout, align: layout.align.abi }
+ Ok(MPlaceTy { mplace, layout, align: layout.align.abi })
}
/// Writes the aggregate to the destination.
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(cell_leak)]
+#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(hash_raw_entry)]
#![feature(hasher_prefixfree_extras)]
use std::collections::hash_map::Entry;
use std::error::Error;
use std::fs;
+use std::intrinsics::unlikely;
use std::path::Path;
use std::process;
use std::sync::Arc;
/// Record a query in-memory cache hit.
#[inline(always)]
pub fn query_cache_hit(&self, query_invocation_id: QueryInvocationId) {
- self.instant_query_event(
- |profiler| profiler.query_cache_hit_event_kind,
- query_invocation_id,
- EventFilter::QUERY_CACHE_HITS,
- );
+ #[inline(never)]
+ #[cold]
+ fn cold_call(profiler_ref: &SelfProfilerRef, query_invocation_id: QueryInvocationId) {
+ profiler_ref.instant_query_event(
+ |profiler| profiler.query_cache_hit_event_kind,
+ query_invocation_id,
+ );
+ }
+
+ if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
+ cold_call(self, query_invocation_id);
+ }
}
/// Start profiling a query being blocked on a concurrent execution.
&self,
event_kind: fn(&SelfProfiler) -> StringId,
query_invocation_id: QueryInvocationId,
- event_filter: EventFilter,
) {
- drop(self.exec(event_filter, |profiler| {
- let event_id = StringId::new_virtual(query_invocation_id.0);
- let thread_id = get_thread_id();
-
- profiler.profiler.record_instant_event(
- event_kind(profiler),
- EventId::from_virtual(event_id),
- thread_id,
- );
-
- TimingGuard::none()
- }));
+ let event_id = StringId::new_virtual(query_invocation_id.0);
+ let thread_id = get_thread_id();
+ let profiler = self.profiler.as_ref().unwrap();
+ profiler.profiler.record_instant_event(
+ event_kind(profiler),
+ EventId::from_virtual(event_id),
+ thread_id,
+ );
}
pub fn with_profiler(&self, f: impl FnOnce(&SelfProfiler)) {
registry: diagnostics_registry(),
};
- if !tracing::dispatcher::has_been_set() {
- init_rustc_env_logger_with_backtrace_option(&config.opts.unstable_opts.log_backtrace);
- }
-
match make_input(config.opts.error_format, &matches.free) {
Err(reported) => return Err(reported),
Ok(Some(input)) => {
}
}
- let mut gctxt = queries.global_ctxt()?;
+ // Make sure name resolution and macro expansion is run.
+ queries.global_ctxt()?;
+
if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
return early_exit();
}
// Make sure the `output_filenames` query is run for its side
// effects of writing the dep-info and reporting errors.
- gctxt.enter(|tcx| tcx.output_filenames(()));
+ queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(()));
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
&& sess.opts.output_types.len() == 1
return early_exit();
}
- gctxt.enter(|tcx| {
+ queries.global_ctxt()?.enter(|tcx| {
let result = tcx.analysis(());
if sess.opts.unstable_opts.save_analysis {
let crate_name = tcx.crate_name(LOCAL_CRATE);
result
})?;
- drop(gctxt);
-
if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
return early_exit();
}
if !info.payload().is::<rustc_errors::ExplicitBug>()
&& !info.payload().is::<rustc_errors::DelayedBugPanic>()
{
- let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
- handler.emit_diagnostic(&mut d);
+ handler.emit_err(session_diagnostics::Ice);
}
- handler.emit_note(session_diagnostics::Ice);
handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
handler.emit_note(session_diagnostics::IceVersion {
version: util::version_str!().unwrap_or("unknown_version"),
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
- init_rustc_env_logger_with_backtrace_option(&None);
-}
-
-/// This allows tools to enable rust logging without having to magically match rustc's
-/// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to
-/// choose a target module you wish to show backtraces along with its logging.
-pub fn init_rustc_env_logger_with_backtrace_option(backtrace_target: &Option<String>) {
- if let Err(error) = rustc_log::init_rustc_env_logger_with_backtrace_option(backtrace_target) {
- early_error(ErrorOutputType::default(), &error.to_string());
- }
+ init_env_logger("RUSTC_LOG");
}
/// This allows tools to enable rust logging without having to magically match rustc's
pub fn main() -> ! {
let start_time = Instant::now();
let start_rss = get_resident_set_size();
+ init_rustc_env_logger();
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook();
}
}
- pub fn trait_bound(&self, path: ast::Path) -> ast::GenericBound {
+ pub fn trait_bound(&self, path: ast::Path, is_const: bool) -> ast::GenericBound {
ast::GenericBound::Trait(
self.poly_trait_ref(path.span, path),
- ast::TraitBoundModifier::None,
+ if is_const {
+ ast::TraitBoundModifier::MaybeConst
+ } else {
+ ast::TraitBoundModifier::None
+ },
)
}
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;
- PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0);
+ PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None;
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
let mut wf_tys = FxIndexSet::default();
- let unnormalized_impl_sig = infcx.replace_bound_vars_with_fresh_vars(
+ let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
tcx.fn_sig(impl_m.def_id).subst_identity(),
let impl_sig = ocx.normalize(
&norm_cause,
param_env,
- infcx.replace_bound_vars_with_fresh_vars(
+ infcx.instantiate_binder_with_fresh_vars(
return_span,
infer::HigherRankedType,
tcx.fn_sig(impl_m.def_id).subst_identity(),
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(substs).is_none() {
let closure_sig = substs.as_closure().sig();
- let closure_sig = self.replace_bound_vars_with_fresh_vars(
+ let closure_sig = self.instantiate_binder_with_fresh_vars(
call_expr.span,
infer::FnCall,
closure_sig,
// renormalize the associated types at this point, since they
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
- let fn_sig = self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
+ let fn_sig = self.instantiate_binder_with_fresh_vars(call_expr.span, infer::FnCall, fn_sig);
let fn_sig = self.normalize(call_expr.span, fn_sig);
// Call the generic checker.
)
.map(|(hir_ty, &supplied_ty)| {
// Instantiate (this part of..) S to S', i.e., with fresh variables.
- self.replace_bound_vars_with_fresh_vars(
+ self.instantiate_binder_with_fresh_vars(
hir_ty.span,
LateBoundRegionConversionTime::FnCall,
// (*) binder moved to here
all_obligations.extend(obligations);
}
- let supplied_output_ty = self.replace_bound_vars_with_fresh_vars(
+ let supplied_output_ty = self.instantiate_binder_with_fresh_vars(
decl.output.span(),
LateBoundRegionConversionTime::FnCall,
supplied_sig.output(),
self.cause.clone(),
self.param_env,
ty::Binder::dummy(
- self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]),
+ self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
),
));
// placeholder lifetimes with probing, we just replace higher lifetimes
// with fresh vars.
let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
- let input = self.replace_bound_vars_with_fresh_vars(
+ let input = self.instantiate_binder_with_fresh_vars(
span,
infer::LateBoundRegionConversionTime::FnCall,
fn_sig.input(i),
// Also, as we just want to check sizedness, instead of introducing
// placeholder lifetimes with probing, we just replace higher lifetimes
// with fresh vars.
- let output = self.replace_bound_vars_with_fresh_vars(
+ let output = self.instantiate_binder_with_fresh_vars(
expr.span,
infer::LateBoundRegionConversionTime::FnCall,
fn_sig.output(),
use crate::FnCtxt;
use rustc_hir as hir;
use rustc_hir::def::Res;
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_middle::ty::{self, DefIdTree, Ty, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{self, Span};
use rustc_trait_selection::traits;
+use std::ops::ControlFlow;
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub fn adjust_fulfillment_error_for_expr_obligation(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ ) -> bool {
+ let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
+ = *error.obligation.cause.code().peel_derives() else { return false; };
+ let hir = self.tcx.hir();
+ let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
+
+ let Some(unsubstituted_pred) =
+ self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
+ else { return false; };
+
+ let generics = self.tcx.generics_of(def_id);
+ let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
+ ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
+ _ => ty::List::empty(),
+ };
+
+ let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
+ predicate_substs.types().find_map(|ty| {
+ ty.walk().find_map(|arg| {
+ if let ty::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Param(param_ty) = ty.kind()
+ && matches(param_ty)
+ {
+ Some(arg)
+ } else {
+ None
+ }
+ })
+ })
+ };
+
+ // Prefer generics that are local to the fn item, since these are likely
+ // to be the cause of the unsatisfied predicate.
+ let mut param_to_point_at = find_param_matching(&|param_ty| {
+ self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
+ });
+ // Fall back to generic that isn't local to the fn item. This will come
+ // from a trait or impl, for example.
+ let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
+ self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
+ && param_ty.name != rustc_span::symbol::kw::SelfUpper
+ });
+ // Finally, the `Self` parameter is possibly the reason that the predicate
+ // is unsatisfied. This is less likely to be true for methods, because
+ // method probe means that we already kinda check that the predicates due
+ // to the `Self` type are true.
+ let mut self_param_to_point_at =
+ find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
+
+ // Finally, for ambiguity-related errors, we actually want to look
+ // for a parameter that is the source of the inference type left
+ // over in this predicate.
+ if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+ fallback_param_to_point_at = None;
+ self_param_to_point_at = None;
+ param_to_point_at =
+ self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
+ }
+
+ if self.closure_span_overlaps_error(error, expr.span) {
+ return false;
+ }
+
+ match &expr.kind {
+ hir::ExprKind::Path(qpath) => {
+ if let hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Call(callee, args),
+ hir_id: call_hir_id,
+ span: call_span,
+ ..
+ }) = hir.get_parent(expr.hir_id)
+ && callee.hir_id == expr.hir_id
+ {
+ if self.closure_span_overlaps_error(error, *call_span) {
+ return false;
+ }
+
+ for param in
+ [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
+ {
+ if self.blame_specific_arg_if_possible(
+ error,
+ def_id,
+ param,
+ *call_hir_id,
+ callee.span,
+ None,
+ args,
+ )
+ {
+ return true;
+ }
+ }
+ }
+ // Notably, we only point to params that are local to the
+ // item we're checking, since those are the ones we are able
+ // to look in the final `hir::PathSegment` for. Everything else
+ // would require a deeper search into the `qpath` than I think
+ // is worthwhile.
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+ {
+ return true;
+ }
+ }
+ hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
+ for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
+ {
+ if self.blame_specific_arg_if_possible(
+ error,
+ def_id,
+ param,
+ hir_id,
+ segment.ident.span,
+ Some(receiver),
+ args,
+ ) {
+ return true;
+ }
+ }
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
+ {
+ return true;
+ }
+ }
+ hir::ExprKind::Struct(qpath, fields, ..) => {
+ if let Res::Def(
+ hir::def::DefKind::Struct | hir::def::DefKind::Variant,
+ variant_def_id,
+ ) = self.typeck_results.borrow().qpath_res(qpath, hir_id)
+ {
+ for param in
+ [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ {
+ if let Some(param) = param {
+ let refined_expr = self.point_at_field_if_possible(
+ def_id,
+ param,
+ variant_def_id,
+ fields,
+ );
+
+ match refined_expr {
+ None => {}
+ Some((refined_expr, _)) => {
+ error.obligation.cause.span = refined_expr
+ .span
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(refined_expr.span);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if let Some(param_to_point_at) = param_to_point_at
+ && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
+ {
+ return true;
+ }
+ }
+ _ => {}
+ }
+
+ false
+ }
+
+ fn point_at_path_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param: ty::GenericArg<'tcx>,
+ qpath: &hir::QPath<'tcx>,
+ ) -> bool {
+ match qpath {
+ hir::QPath::Resolved(_, path) => {
+ if let Some(segment) = path.segments.last()
+ && self.point_at_generic_if_possible(error, def_id, param, segment)
+ {
+ return true;
+ }
+ }
+ hir::QPath::TypeRelative(_, segment) => {
+ if self.point_at_generic_if_possible(error, def_id, param, segment) {
+ return true;
+ }
+ }
+ _ => {}
+ }
+
+ false
+ }
+
+ fn point_at_generic_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ segment: &hir::PathSegment<'tcx>,
+ ) -> bool {
+ let own_substs = self
+ .tcx
+ .generics_of(def_id)
+ .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
+ let Some((index, _)) = own_substs
+ .iter()
+ .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
+ .enumerate()
+ .find(|(_, arg)| **arg == param_to_point_at) else { return false };
+ let Some(arg) = segment
+ .args()
+ .args
+ .iter()
+ .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
+ .nth(index) else { return false; };
+ error.obligation.cause.span = arg
+ .span()
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(arg.span());
+ true
+ }
+
+ fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
+ &self,
+ item_def_id: DefId,
+ t: T,
+ ) -> Option<ty::GenericArg<'tcx>> {
+ struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
+ impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
+ type BreakTy = ty::GenericArg<'tcx>;
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
+ if let Some(origin) = self.0.type_var_origin(ty)
+ && let rustc_infer::infer::type_variable::TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
+ origin.kind
+ && let generics = self.0.tcx.generics_of(self.1)
+ && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
+ && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
+ .get(index as usize)
+ {
+ ControlFlow::Break(*subst)
+ } else {
+ ty.super_visit_with(self)
+ }
+ }
+ }
+ t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
+ }
+
+ fn closure_span_overlaps_error(
+ &self,
+ error: &traits::FulfillmentError<'tcx>,
+ span: Span,
+ ) -> bool {
+ if let traits::FulfillmentErrorCode::CodeSelectionError(
+ traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+ ) = error.code
+ && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+ && span.overlaps(self.tcx.def_span(*def_id))
+ {
+ true
+ } else {
+ false
+ }
+ }
+
+ fn point_at_field_if_possible(
+ &self,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ variant_def_id: DefId,
+ expr_fields: &[hir::ExprField<'tcx>],
+ ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
+ let def = self.tcx.adt_def(def_id);
+
+ let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
+ let fields_referencing_param: Vec<_> = def
+ .variant_with_id(variant_def_id)
+ .fields
+ .iter()
+ .filter(|field| {
+ let field_ty = field.ty(self.tcx, identity_substs);
+ Self::find_param_in_ty(field_ty.into(), param_to_point_at)
+ })
+ .collect();
+
+ if let [field] = fields_referencing_param.as_slice() {
+ for expr_field in expr_fields {
+ // Look for the ExprField that matches the field, using the
+ // same rules that check_expr_struct uses for macro hygiene.
+ if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
+ {
+ return Some((expr_field.expr, self.tcx.type_of(field.did)));
+ }
+ }
+ }
+
+ None
+ }
+
+ /// - `blame_specific_*` means that the function will recursively traverse the expression,
+ /// looking for the most-specific-possible span to blame.
+ ///
+ /// - `point_at_*` means that the function will only go "one level", pointing at the specific
+ /// expression mentioned.
+ ///
+ /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
+ /// the provided function call expression, and mark it as responsible for the fullfillment
+ /// error.
+ fn blame_specific_arg_if_possible(
+ &self,
+ error: &mut traits::FulfillmentError<'tcx>,
+ def_id: DefId,
+ param_to_point_at: ty::GenericArg<'tcx>,
+ call_hir_id: hir::HirId,
+ callee_span: Span,
+ receiver: Option<&'tcx hir::Expr<'tcx>>,
+ args: &'tcx [hir::Expr<'tcx>],
+ ) -> bool {
+ let ty = self.tcx.type_of(def_id);
+ if !ty.is_fn() {
+ return false;
+ }
+ let sig = ty.fn_sig(self.tcx).skip_binder();
+ let args_referencing_param: Vec<_> = sig
+ .inputs()
+ .iter()
+ .enumerate()
+ .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
+ .collect();
+ // If there's one field that references the given generic, great!
+ if let [(idx, _)] = args_referencing_param.as_slice()
+ && let Some(arg) = receiver
+ .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
+
+ error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
+
+ if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
+ // This is more specific than pointing at the entire argument.
+ self.blame_specific_expr_if_possible(error, arg_expr)
+ }
+
+ error.obligation.cause.map_code(|parent_code| {
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id: arg.hir_id,
+ call_hir_id,
+ parent_code,
+ }
+ });
+ return true;
+ } else if args_referencing_param.len() > 0 {
+ // If more than one argument applies, then point to the callee span at least...
+ // We have chance to fix this up further in `point_at_generics_if_possible`
+ error.obligation.cause.span = callee_span;
+ }
+
+ false
+ }
+
/**
* Recursively searches for the most-specific blamable expression.
* For example, if you have a chain of constraints like:
use rustc_infer::infer::TypeTrace;
use rustc_middle::ty::adjustment::AllowTwoPhase;
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
use rustc_session::Session;
use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, sym, Span};
use std::mem;
use std::slice;
-use std::ops::ControlFlow;
-
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_casts(&mut self) {
// don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
}
}
- fn adjust_fulfillment_error_for_expr_obligation(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- ) -> bool {
- let (traits::ExprItemObligation(def_id, hir_id, idx) | traits::ExprBindingObligation(def_id, _, hir_id, idx))
- = *error.obligation.cause.code().peel_derives() else { return false; };
- let hir = self.tcx.hir();
- let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; };
-
- let Some(unsubstituted_pred) =
- self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx)
- else { return false; };
-
- let generics = self.tcx.generics_of(def_id);
- let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => pred.trait_ref.substs,
- ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => pred.projection_ty.substs,
- _ => ty::List::empty(),
- };
-
- let find_param_matching = |matches: &dyn Fn(&ty::ParamTy) -> bool| {
- predicate_substs.types().find_map(|ty| {
- ty.walk().find_map(|arg| {
- if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Param(param_ty) = ty.kind()
- && matches(param_ty)
- {
- Some(arg)
- } else {
- None
- }
- })
- })
- };
-
- // Prefer generics that are local to the fn item, since these are likely
- // to be the cause of the unsatisfied predicate.
- let mut param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) == def_id
- });
- // Fall back to generic that isn't local to the fn item. This will come
- // from a trait or impl, for example.
- let mut fallback_param_to_point_at = find_param_matching(&|param_ty| {
- self.tcx.parent(generics.type_param(param_ty, self.tcx).def_id) != def_id
- && param_ty.name != rustc_span::symbol::kw::SelfUpper
- });
- // Finally, the `Self` parameter is possibly the reason that the predicate
- // is unsatisfied. This is less likely to be true for methods, because
- // method probe means that we already kinda check that the predicates due
- // to the `Self` type are true.
- let mut self_param_to_point_at =
- find_param_matching(&|param_ty| param_ty.name == rustc_span::symbol::kw::SelfUpper);
-
- // Finally, for ambiguity-related errors, we actually want to look
- // for a parameter that is the source of the inference type left
- // over in this predicate.
- if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
- fallback_param_to_point_at = None;
- self_param_to_point_at = None;
- param_to_point_at =
- self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
- }
-
- if self.closure_span_overlaps_error(error, expr.span) {
- return false;
- }
-
- match &expr.kind {
- hir::ExprKind::Path(qpath) => {
- if let hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Call(callee, args),
- hir_id: call_hir_id,
- span: call_span,
- ..
- }) = hir.get_parent(expr.hir_id)
- && callee.hir_id == expr.hir_id
- {
- if self.closure_span_overlaps_error(error, *call_span) {
- return false;
- }
-
- for param in
- [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- .into_iter()
- .flatten()
- {
- if self.blame_specific_arg_if_possible(
- error,
- def_id,
- param,
- *call_hir_id,
- callee.span,
- None,
- args,
- )
- {
- return true;
- }
- }
- }
- // Notably, we only point to params that are local to the
- // item we're checking, since those are the ones we are able
- // to look in the final `hir::PathSegment` for. Everything else
- // would require a deeper search into the `qpath` than I think
- // is worthwhile.
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
- {
- return true;
- }
- }
- hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
- for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- .into_iter()
- .flatten()
- {
- if self.blame_specific_arg_if_possible(
- error,
- def_id,
- param,
- hir_id,
- segment.ident.span,
- Some(receiver),
- args,
- ) {
- return true;
- }
- }
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
- {
- return true;
- }
- }
- hir::ExprKind::Struct(qpath, fields, ..) => {
- if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
- self.typeck_results.borrow().qpath_res(qpath, hir_id)
- {
- for param in
- [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
- {
- if let Some(param) = param {
- let refined_expr = self.point_at_field_if_possible(
- def_id,
- param,
- variant_def_id,
- fields,
- );
-
- match refined_expr {
- None => {}
- Some((refined_expr, _)) => {
- error.obligation.cause.span = refined_expr
- .span
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(refined_expr.span);
- return true;
- }
- }
- }
- }
- }
- if let Some(param_to_point_at) = param_to_point_at
- && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath)
- {
- return true;
- }
- }
- _ => {}
- }
-
- false
- }
-
- fn closure_span_overlaps_error(
- &self,
- error: &traits::FulfillmentError<'tcx>,
- span: Span,
- ) -> bool {
- if let traits::FulfillmentErrorCode::CodeSelectionError(
- traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
- ) = error.code
- && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
- && span.overlaps(self.tcx.def_span(*def_id))
- {
- true
- } else {
- false
- }
- }
-
- /// - `blame_specific_*` means that the function will recursively traverse the expression,
- /// looking for the most-specific-possible span to blame.
- ///
- /// - `point_at_*` means that the function will only go "one level", pointing at the specific
- /// expression mentioned.
- ///
- /// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
- /// the provided function call expression, and mark it as responsible for the fullfillment
- /// error.
- fn blame_specific_arg_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- call_hir_id: hir::HirId,
- callee_span: Span,
- receiver: Option<&'tcx hir::Expr<'tcx>>,
- args: &'tcx [hir::Expr<'tcx>],
- ) -> bool {
- let ty = self.tcx.type_of(def_id);
- if !ty.is_fn() {
- return false;
- }
- let sig = ty.fn_sig(self.tcx).skip_binder();
- let args_referencing_param: Vec<_> = sig
- .inputs()
- .iter()
- .enumerate()
- .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at))
- .collect();
- // If there's one field that references the given generic, great!
- if let [(idx, _)] = args_referencing_param.as_slice()
- && let Some(arg) = receiver
- .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
-
- error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
-
- if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) {
- // This is more specific than pointing at the entire argument.
- self.blame_specific_expr_if_possible(error, arg_expr)
- }
-
- error.obligation.cause.map_code(|parent_code| {
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: arg.hir_id,
- call_hir_id,
- parent_code,
- }
- });
- return true;
- } else if args_referencing_param.len() > 0 {
- // If more than one argument applies, then point to the callee span at least...
- // We have chance to fix this up further in `point_at_generics_if_possible`
- error.obligation.cause.span = callee_span;
- }
-
- false
- }
-
- // FIXME: Make this private and move to mod adjust_fulfillment_errors
- pub fn point_at_field_if_possible(
- &self,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- variant_def_id: DefId,
- expr_fields: &[hir::ExprField<'tcx>],
- ) -> Option<(&'tcx hir::Expr<'tcx>, Ty<'tcx>)> {
- let def = self.tcx.adt_def(def_id);
-
- let identity_substs = ty::InternalSubsts::identity_for_item(self.tcx, def_id);
- let fields_referencing_param: Vec<_> = def
- .variant_with_id(variant_def_id)
- .fields
- .iter()
- .filter(|field| {
- let field_ty = field.ty(self.tcx, identity_substs);
- Self::find_param_in_ty(field_ty.into(), param_to_point_at)
- })
- .collect();
-
- if let [field] = fields_referencing_param.as_slice() {
- for expr_field in expr_fields {
- // Look for the ExprField that matches the field, using the
- // same rules that check_expr_struct uses for macro hygiene.
- if self.tcx.adjust_ident(expr_field.ident, variant_def_id) == field.ident(self.tcx)
- {
- return Some((expr_field.expr, self.tcx.type_of(field.did)));
- }
- }
- }
-
- None
- }
-
- fn point_at_path_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param: ty::GenericArg<'tcx>,
- qpath: &QPath<'tcx>,
- ) -> bool {
- match qpath {
- hir::QPath::Resolved(_, path) => {
- if let Some(segment) = path.segments.last()
- && self.point_at_generic_if_possible(error, def_id, param, segment)
- {
- return true;
- }
- }
- hir::QPath::TypeRelative(_, segment) => {
- if self.point_at_generic_if_possible(error, def_id, param, segment) {
- return true;
- }
- }
- _ => {}
- }
-
- false
- }
-
- fn point_at_generic_if_possible(
- &self,
- error: &mut traits::FulfillmentError<'tcx>,
- def_id: DefId,
- param_to_point_at: ty::GenericArg<'tcx>,
- segment: &hir::PathSegment<'tcx>,
- ) -> bool {
- let own_substs = self
- .tcx
- .generics_of(def_id)
- .own_substs(ty::InternalSubsts::identity_for_item(self.tcx, def_id));
- let Some((index, _)) = own_substs
- .iter()
- .filter(|arg| matches!(arg.unpack(), ty::GenericArgKind::Type(_)))
- .enumerate()
- .find(|(_, arg)| **arg == param_to_point_at) else { return false };
- let Some(arg) = segment
- .args()
- .args
- .iter()
- .filter(|arg| matches!(arg, hir::GenericArg::Type(_)))
- .nth(index) else { return false; };
- error.obligation.cause.span = arg
- .span()
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(arg.span());
- true
- }
-
- fn find_ambiguous_parameter_in<T: TypeVisitable<'tcx>>(
- &self,
- item_def_id: DefId,
- t: T,
- ) -> Option<ty::GenericArg<'tcx>> {
- struct FindAmbiguousParameter<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, DefId);
- impl<'tcx> TypeVisitor<'tcx> for FindAmbiguousParameter<'_, 'tcx> {
- type BreakTy = ty::GenericArg<'tcx>;
- fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
- if let Some(origin) = self.0.type_var_origin(ty)
- && let TypeVariableOriginKind::TypeParameterDefinition(_, Some(def_id)) =
- origin.kind
- && let generics = self.0.tcx.generics_of(self.1)
- && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id)
- && let Some(subst) = ty::InternalSubsts::identity_for_item(self.0.tcx, self.1)
- .get(index as usize)
- {
- ControlFlow::Break(*subst)
- } else {
- ty.super_visit_with(self)
- }
- }
- }
- t.visit_with(&mut FindAmbiguousParameter(self, item_def_id)).break_value()
- }
-
fn label_fn_like(
&self,
err: &mut Diagnostic,
item_segment: &hir::PathSegment<'_>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Ty<'tcx> {
- let trait_ref = self.replace_bound_vars_with_fresh_vars(
+ let trait_ref = self.instantiate_binder_with_fresh_vars(
span,
infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
poly_trait_ref,
hir::Path { segments: [segment], .. },
))
| hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
- let self_ty = self.astconv().ast_ty_to_ty(ty);
- if let Ok(pick) = self.probe_for_name(
- Mode::Path,
- Ident::new(capitalized_name, segment.ident.span),
- Some(expected_ty),
- IsSuggestion(true),
- self_ty,
- expr.hir_id,
- ProbeScope::TraitsInScope,
- ) {
+ if let Some(self_ty) = self.typeck_results.borrow().node_type_opt(ty.hir_id)
+ && let Ok(pick) = self.probe_for_name(
+ Mode::Path,
+ Ident::new(capitalized_name, segment.ident.span),
+ Some(expected_ty),
+ IsSuggestion(true),
+ self_ty,
+ expr.hir_id,
+ ProbeScope::TraitsInScope,
+ )
+ {
(pick.item, segment)
} else {
return false;
let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty);
let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id);
let upcast_trait_ref =
- this.replace_bound_vars_with_fresh_vars(upcast_poly_trait_ref);
+ this.instantiate_binder_with_fresh_vars(upcast_poly_trait_ref);
debug!(
"original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
original_poly_trait_ref, upcast_trait_ref, trait_def_id
probe::WhereClausePick(poly_trait_ref) => {
// Where clauses can have bound regions in them. We need to instantiate
// those to convert from a poly-trait-ref to a trait-ref.
- self.replace_bound_vars_with_fresh_vars(poly_trait_ref).substs
+ self.instantiate_binder_with_fresh_vars(poly_trait_ref).substs
}
}
}
let sig = self.tcx.fn_sig(def_id).subst(self.tcx, all_substs);
debug!("type scheme substituted, sig={:?}", sig);
- let sig = self.replace_bound_vars_with_fresh_vars(sig);
+ let sig = self.instantiate_binder_with_fresh_vars(sig);
debug!("late-bound lifetimes from method instantiated, sig={:?}", sig);
(sig, method_predicates)
upcast_trait_refs.into_iter().next().unwrap()
}
- fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
+ fn instantiate_binder_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<'tcx> + Copy,
{
- self.fcx.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, value)
+ self.fcx.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, value)
}
}
// with bound regions.
let fn_sig = tcx.fn_sig(def_id).subst(self.tcx, substs);
let fn_sig =
- self.replace_bound_vars_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
+ self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
let InferOk { value, obligations: o } =
self.at(&obligation.cause, self.param_env).normalize(fn_sig);
ty::AssocKind::Fn => self.probe(|_| {
let substs = self.fresh_substs_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).subst(self.tcx, substs);
- let fty = self.replace_bound_vars_with_fresh_vars(self.span, infer::FnCall, fty);
+ let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
if let Some(self_ty) = self_ty {
if self
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
- output_query_region_constraints.outlives.push((
- ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r)),
- constraint_category,
- ));
- output_query_region_constraints.outlives.push((
- ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o)),
- constraint_category,
- ));
+ output_query_region_constraints
+ .outlives
+ .push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
+ output_query_region_constraints
+ .outlives
+ .push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
}
}
query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| {
let r_c = substitute_value(self.tcx, &result_subst, r_c);
- // Screen out `'a: 'a` cases -- we skip the binder here but
- // only compare the inner values to one another, so they are still at
- // consistent binding levels.
- let ty::OutlivesPredicate(k1, r2) = r_c.0.skip_binder();
+ // Screen out `'a: 'a` cases.
+ let ty::OutlivesPredicate(k1, r2) = r_c.0;
if k1 != r2.into() { Some(r_c) } else { None }
}),
);
pub fn query_outlives_constraint_to_obligation(
&self,
- predicate: QueryOutlivesConstraint<'tcx>,
+ (predicate, _): QueryOutlivesConstraint<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Obligation<'tcx, ty::Predicate<'tcx>> {
- let ty::OutlivesPredicate(k1, r2) = predicate.0.skip_binder();
+ let ty::OutlivesPredicate(k1, r2) = predicate;
let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
span_bug!(cause.span, "unexpected const outlives {:?}", predicate);
}
};
- let predicate = predicate.0.rebind(atom);
+ let predicate = ty::Binder::dummy(atom);
Obligation::new(self.tcx, cause, param_env, predicate)
}
let outlives: Vec<_> = constraints
.iter()
.map(|(k, origin)| {
- // no bound vars in the code above
- let constraint = ty::Binder::dummy(match *k {
+ let constraint = match *k {
// Swap regions because we are going from sub (<=) to outlives
// (>=).
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1)
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
- });
+ };
(constraint, origin.to_constraint_category())
})
- .chain(
- outlives_obligations
- // no bound vars in the code above
- .map(|(ty, r, constraint_category)| {
- (ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), r)), constraint_category)
- }),
- )
+ .chain(outlives_obligations.map(|(ty, r, constraint_category)| {
+ (ty::OutlivesPredicate(ty.into(), r), constraint_category)
+ }))
.collect();
QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() }
let a_types = infcx.tcx.anonymize_bound_vars(a_types);
let b_types = infcx.tcx.anonymize_bound_vars(b_types);
if a_types.bound_vars() == b_types.bound_vars() {
- let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
);
for (a, b) in std::iter::zip(a_types, b_types) {
// First, we instantiate each bound region in the supertype with a
// fresh placeholder region. Note that this automatically creates
// a new universe if needed.
- let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
+ let sup_prime = self.infcx.instantiate_binder_with_placeholders(sup);
// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
// but no other pre-existing region variables -- can name
// the placeholders.
- let sub_prime = self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
+ let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
debug!("a_prime={:?}", sub_prime);
debug!("b_prime={:?}", sup_prime);
///
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
#[instrument(level = "debug", skip(self), ret)]
- pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
+ pub fn instantiate_binder_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T
where
T: TypeFoldable<'tcx> + Copy,
{
Ok(self.commit_if_ok(|_snapshot| {
let ty::SubtypePredicate { a_is_expected, a, b } =
- self.replace_bound_vars_with_placeholders(predicate);
+ self.instantiate_binder_with_placeholders(predicate);
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
cause: &traits::ObligationCause<'tcx>,
predicate: ty::PolyRegionOutlivesPredicate<'tcx>,
) {
- let ty::OutlivesPredicate(r_a, r_b) = self.replace_bound_vars_with_placeholders(predicate);
+ let ty::OutlivesPredicate(r_a, r_b) = self.instantiate_binder_with_placeholders(predicate);
let origin =
SubregionOrigin::from_obligation_cause(cause, || RelateRegionParamBound(cause.span));
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
value
}
- pub fn replace_bound_vars_with_fresh_vars<T>(
+ // Instantiates the bound variables in a given binder with fresh inference
+ // variables in the current universe.
+ //
+ // Use this method if you'd like to find some substitution of the binder's
+ // variables (e.g. during a method call). If there isn't a [`LateBoundRegionConversionTime`]
+ // that corresponds to your use case, consider whether or not you should
+ // use [`InferCtxt::instantiate_binder_with_placeholders`] instead.
+ pub fn instantiate_binder_with_fresh_vars<T>(
&self,
span: Span,
lbrct: LateBoundRegionConversionTime,
let a_types = infcx.tcx.anonymize_bound_vars(a_types);
let b_types = infcx.tcx.anonymize_bound_vars(b_types);
if a_types.bound_vars() == b_types.bound_vars() {
- let (a_types, b_types) = infcx.replace_bound_vars_with_placeholders(
+ let (a_types, b_types) = infcx.instantiate_binder_with_placeholders(
a_types.map_bound(|a_types| (a_types, b_types.skip_binder())),
);
for (a, b) in std::iter::zip(a_types, b_types) {
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
- tracked!(log_backtrace, Some("filter".to_string()));
tracked!(maximal_hir_to_mir_coverage, true);
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
declare_lint! {
/// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
- /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits.
+ /// (`[u8]`) or string slice field (`str`) is used in a `packed` struct that derives one or
+ /// more built-in traits.
///
/// ### Example
///
/// ### Explanation
///
/// This was previously accepted but is being phased out, because fields in packed structs are
- /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary
- /// exception because certain crates depended on them.
+ /// now required to implement `Copy` for `derive` to work. Byte slices and string slices are a
+ /// temporary exception because certain crates depended on them.
pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
Warn,
- "`[u8]` slice used in a packed struct with `derive`",
+ "`[u8]` or `str` used in a packed struct with `derive`",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Lint.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/Linker/Linker.h"
+#if LLVM_VERSION_GE(16, 0)
+#include "llvm/TargetParser/Triple.h"
+#else
+#include "llvm/ADT/Triple.h"
+#endif
+
extern "C" void LLVMRustSetLastError(const char *);
enum class LLVMRustResult { Success, Failure };
use tracing_subscriber::layer::SubscriberExt;
pub fn init_rustc_env_logger() -> Result<(), Error> {
- init_rustc_env_logger_with_backtrace_option(&None)
-}
-
-pub fn init_rustc_env_logger_with_backtrace_option(
- backtrace_target: &Option<String>,
-) -> Result<(), Error> {
- init_env_logger_with_backtrace_option("RUSTC_LOG", backtrace_target)
+ init_env_logger("RUSTC_LOG")
}
/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) -> Result<(), Error> {
- init_env_logger_with_backtrace_option(env, &None)
-}
-
-pub fn init_env_logger_with_backtrace_option(
- env: &str,
- backtrace_target: &Option<String>,
-) -> Result<(), Error> {
let filter = match env::var(env) {
Ok(env) => EnvFilter::new(env),
_ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
let layer = layer.with_thread_ids(true).with_thread_names(true);
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
- match backtrace_target {
- Some(str) => {
+ match env::var(format!("{env}_BACKTRACE")) {
+ Ok(str) => {
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(io::stderr)
.without_time()
let subscriber = subscriber.with(fmt_layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
}
- None => {
+ Err(_) => {
tracing::subscriber::set_global_default(subscriber).unwrap();
}
};
}
}
-pub type QueryOutlivesConstraint<'tcx> = (
- ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
- ConstraintCategory<'tcx>,
-);
+pub type QueryOutlivesConstraint<'tcx> =
+ (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
TrivialTypeTraversalAndLiftImpls! {
for <'tcx> {
///
/// The exact limit is set by the `const_eval_limit` attribute.
StepLimitReached,
- /// There is not enough memory to perform an allocation.
+ /// There is not enough memory (on the host) to perform an allocation.
MemoryExhausted,
+ /// The address space (of the target) is full.
+ AddressSpaceFull,
}
impl fmt::Display for ResourceExhaustionInfo {
MemoryExhausted => {
write!(f, "tried to allocate more memory than available to compiler")
}
+ AddressSpaceFull => {
+ write!(f, "there are no more free addresses in the address space")
+ }
}
}
}
/// This is because the `hir_crate` query gives you access to all other items.
/// To avoid this fate, do not call `tcx.hir().krate()`; instead,
/// prefer wrappers like `tcx.visit_all_items_in_krate()`.
- query hir_crate(key: ()) -> Crate<'tcx> {
+ query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
arena_cache
eval_always
desc { "getting the crate HIR" }
}
/// All items in the crate.
- query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
+ query hir_crate_items(_: ()) -> &'tcx rustc_middle::hir::ModuleItems {
arena_cache
eval_always
desc { "getting HIR crate items" }
///
/// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
/// Avoid calling this query directly.
- query hir_module_items(key: LocalDefId) -> rustc_middle::hir::ModuleItems {
+ query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems {
arena_cache
desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
separate_provide_extern
}
- query unsizing_params_for_adt(key: DefId) -> rustc_index::bit_set::BitSet<u32>
+ query unsizing_params_for_adt(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32>
{
arena_cache
desc { |tcx|
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
/// associated generics.
- query generics_of(key: DefId) -> ty::Generics {
+ query generics_of(key: DefId) -> &'tcx ty::Generics {
desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
arena_cache
cache_on_disk_if { key.is_local() }
/// These are assembled from the following places:
/// - `extern` blocks (depending on their `link` attributes)
/// - the `libs` (`-l`) option
- query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+ query native_libraries(_: CrateNum) -> &'tcx Vec<NativeLib> {
arena_cache
desc { "looking up the native libraries of a linked crate" }
separate_provide_extern
}
- query shallow_lint_levels_on(key: hir::OwnerId) -> rustc_middle::lint::ShallowLintLevelMap {
+ query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
eval_always // fetches `resolutions`
arena_cache
desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
}
- query lint_expectations(_: ()) -> Vec<(LintExpectationId, LintExpectation)> {
+ query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
arena_cache
desc { "computing `#[expect]`ed lints in this crate" }
}
}
/// Set of param indexes for type params that are in the type's representation
- query params_in_repr(key: DefId) -> rustc_index::bit_set::BitSet<u32> {
+ query params_in_repr(key: DefId) -> &'tcx rustc_index::bit_set::BitSet<u32> {
desc { "finding type parameters in the representation" }
arena_cache
no_hash
}
/// Create a THIR tree for debugging.
- query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
+ query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
no_hash
arena_cache
desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
}
/// Create a list-like THIR representation for debugging.
- query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> String {
+ query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
no_hash
arena_cache
desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
/// Set of all the `DefId`s in this crate that have MIR associated with
/// them. This includes all the body owners, but also things like struct
/// constructors.
- query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
+ query mir_keys(_: ()) -> &'tcx rustc_data_structures::fx::FxIndexSet<LocalDefId> {
arena_cache
desc { "getting a list of all mir_keys" }
}
query symbols_for_closure_captures(
key: (LocalDefId, LocalDefId)
- ) -> Vec<rustc_span::Symbol> {
+ ) -> &'tcx Vec<rustc_span::Symbol> {
arena_cache
desc {
|tcx| "finding symbols for captures of closure `{}` in `{}`",
}
}
- query mir_generator_witnesses(key: DefId) -> mir::GeneratorLayout<'tcx> {
+ query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
arena_cache
desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
/// MIR pass (assuming the -Cinstrument-coverage option is enabled).
- query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
+ query coverageinfo(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageInfo {
desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
arena_cache
}
/// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
/// function was optimized out before codegen, and before being added to the Coverage Map.
- query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+ query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> {
desc {
|tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`",
tcx.def_path_str(key)
desc { "erasing regions from `{}`", ty }
}
- query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
+ query wasm_import_module_map(_: CrateNum) -> &'tcx FxHashMap<DefId, String> {
arena_cache
desc { "getting wasm import module map" }
}
desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
}
- query trait_def(key: DefId) -> ty::TraitDef {
+ query trait_def(key: DefId) -> &'tcx ty::TraitDef {
desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
arena_cache
cache_on_disk_if { key.is_local() }
}
/// Gets a map with the variance of every item; use `item_variance` instead.
- query crate_variances(_: ()) -> ty::CrateVariancesMap<'tcx> {
+ query crate_variances(_: ()) -> &'tcx ty::CrateVariancesMap<'tcx> {
arena_cache
desc { "computing the variances for items in this crate" }
}
}
/// Maps from thee `DefId` of a type to its (inferred) outlives.
- query inferred_outlives_crate(_: ()) -> ty::CratePredicatesMap<'tcx> {
+ query inferred_outlives_crate(_: ()) -> &'tcx ty::CratePredicatesMap<'tcx> {
arena_cache
desc { "computing the inferred outlives predicates for items in this crate" }
}
}
/// Maps from a trait item to the trait item "descriptor".
- query associated_item(key: DefId) -> ty::AssocItem {
+ query associated_item(key: DefId) -> &'tcx ty::AssocItem {
desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
arena_cache
cache_on_disk_if { key.is_local() }
}
/// Collects the associated items defined on a trait or impl.
- query associated_items(key: DefId) -> ty::AssocItems<'tcx> {
+ query associated_items(key: DefId) -> &'tcx ty::AssocItems<'tcx> {
arena_cache
desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
}
///
/// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
///`{ trait_f: impl_f, trait_g: impl_g }`
- query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
+ query impl_item_implementor_ids(impl_id: DefId) -> &'tcx FxHashMap<DefId, DefId> {
arena_cache
desc { |tcx| "comparing impl items against trait for `{}`", tcx.def_path_str(impl_id) }
}
///
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
/// their respective impl (i.e., part of the derive macro)
- query live_symbols_and_ignored_derived_traits(_: ()) -> (
+ query live_symbols_and_ignored_derived_traits(_: ()) -> &'tcx (
FxHashSet<LocalDefId>,
FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
) {
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
- query crate_inherent_impls(k: ()) -> CrateInherentImpls {
+ query crate_inherent_impls(k: ()) -> &'tcx CrateInherentImpls {
arena_cache
desc { "finding all inherent impls defined in crate" }
}
desc { "checking for private elements in public interfaces" }
}
- query reachable_set(_: ()) -> FxHashSet<LocalDefId> {
+ query reachable_set(_: ()) -> &'tcx FxHashSet<LocalDefId> {
arena_cache
desc { "reachability" }
}
}
/// Generates a MIR body for the shim.
- query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
+ query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> {
arena_cache
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
}
separate_provide_extern
}
- query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
+ query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs {
desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
arena_cache
cache_on_disk_if { def_id.is_local() }
}
/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
- query rendered_const(def_id: DefId) -> String {
+ query rendered_const(def_id: DefId) -> &'tcx String {
arena_cache
desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
cache_on_disk_if { def_id.is_local() }
}
/// Given a trait `trait_id`, return all known `impl` blocks.
- query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
+ query trait_impls_of(trait_id: DefId) -> &'tcx ty::trait_def::TraitImpls {
arena_cache
desc { |tcx| "finding trait impls of `{}`", tcx.def_path_str(trait_id) }
}
- query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
+ query specialization_graph_of(trait_id: DefId) -> &'tcx specialization_graph::Graph {
arena_cache
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
separate_provide_extern
}
- query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+ query dependency_formats(_: ()) -> &'tcx Lrc<crate::middle::dependency_format::Dependencies> {
arena_cache
desc { "getting the linkage format of all dependencies" }
}
// Does not include external symbols that don't have a corresponding DefId,
// like the compiler-generated `main` function and so on.
query reachable_non_generics(_: CrateNum)
- -> DefIdMap<SymbolExportInfo> {
+ -> &'tcx DefIdMap<SymbolExportInfo> {
arena_cache
desc { "looking up the exported symbols of a crate" }
separate_provide_extern
/// added or removed in any upstream crate. Instead use the narrower
/// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
/// better, `Instance::upstream_monomorphization()`.
- query upstream_monomorphizations(_: ()) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
+ query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
arena_cache
desc { "collecting available upstream monomorphizations" }
}
query upstream_monomorphizations_for(def_id: DefId)
-> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
{
- arena_cache
desc { |tcx|
"collecting available upstream monomorphizations for `{}`",
tcx.def_path_str(def_id),
}
/// Returns a list of all `extern` blocks of a crate.
- query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+ query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
arena_cache
desc { "looking up the foreign modules of a linked crate" }
separate_provide_extern
/// Gets the extra data to put in each output filename for a crate.
/// For example, compiling the `foo` crate with `extra-filename=-a` creates a `libfoo-b.rlib` file.
- query extra_filename(_: CrateNum) -> String {
+ query extra_filename(_: CrateNum) -> &'tcx String {
arena_cache
eval_always
desc { "looking up the extra filename for a crate" }
}
/// Gets the paths where the crate came from in the file system.
- query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+ query crate_extern_paths(_: CrateNum) -> &'tcx Vec<PathBuf> {
arena_cache
eval_always
desc { "looking up the paths for extern crates" }
/// Does lifetime resolution on items. Importantly, we can't resolve
/// lifetimes directly on things like trait methods, because of trait params.
/// See `rustc_resolve::late::lifetimes for details.
- query resolve_lifetimes(_: hir::OwnerId) -> ResolveLifetimes {
+ query resolve_lifetimes(_: hir::OwnerId) -> &'tcx ResolveLifetimes {
arena_cache
desc { "resolving lifetimes" }
}
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
- query lib_features(_: ()) -> LibFeatures {
+ query lib_features(_: ()) -> &'tcx LibFeatures {
arena_cache
desc { "calculating the lib features map" }
}
desc { "calculating the lib features defined in a crate" }
separate_provide_extern
}
- query stability_implications(_: CrateNum) -> FxHashMap<Symbol, Symbol> {
+ query stability_implications(_: CrateNum) -> &'tcx FxHashMap<Symbol, Symbol> {
arena_cache
desc { "calculating the implications between `#[unstable]` features defined in a crate" }
separate_provide_extern
separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata.
- query get_lang_items(_: ()) -> LanguageItems {
+ query get_lang_items(_: ()) -> &'tcx LanguageItems {
arena_cache
eval_always
desc { "calculating the lang items map" }
}
/// Returns all diagnostic items defined in all crates.
- query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems {
+ query all_diagnostic_items(_: ()) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
arena_cache
eval_always
desc { "calculating the diagnostic items map" }
}
/// Returns the diagnostic items defined in a crate.
- query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
+ query diagnostic_items(_: CrateNum) -> &'tcx rustc_hir::diagnostic_items::DiagnosticItems {
arena_cache
desc { "calculating the diagnostic items map in a crate" }
separate_provide_extern
desc { "calculating the missing lang items in a crate" }
separate_provide_extern
}
- query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+ query visible_parent_map(_: ()) -> &'tcx DefIdMap<DefId> {
arena_cache
desc { "calculating the visible parent map" }
}
- query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
+ query trimmed_def_paths(_: ()) -> &'tcx FxHashMap<DefId, Symbol> {
arena_cache
desc { "calculating trimmed def paths" }
}
desc { "seeing if we're missing an `extern crate` item for this crate" }
separate_provide_extern
}
- query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+ query used_crate_source(_: CrateNum) -> &'tcx Lrc<CrateSource> {
arena_cache
eval_always
desc { "looking at the source for a crate" }
separate_provide_extern
}
/// Returns the debugger visualizers defined for this crate.
- query debugger_visualizers(_: CrateNum) -> Vec<rustc_span::DebuggerVisualizerFile> {
+ query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
arena_cache
desc { "looking up the debugger visualizers for this crate" }
separate_provide_extern
desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
}
- query stability_index(_: ()) -> stability::Index {
+ query stability_index(_: ()) -> &'tcx stability::Index {
arena_cache
eval_always
desc { "calculating the stability index for the local crate" }
///
/// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
/// has been destroyed.
- query output_filenames(_: ()) -> Arc<OutputFilenames> {
+ query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
feedable
desc { "getting output filenames" }
arena_cache
remap_env_constness
}
- query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
+ query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
arena_cache
eval_always
desc { "looking up supported target features" }
/// span) for an *existing* error. Therefore, it is best-effort, and may never handle
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
/// because the `ty::Ty`-based wfcheck is always run.
- query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+ query diagnostic_hir_wf_check(
+ key: (ty::Predicate<'tcx>, traits::WellFormedLoc)
+ ) -> &'tcx Option<traits::ObligationCause<'tcx>> {
arena_cache
eval_always
no_hash
desc { "performing HIR wf-checking for predicate `{:?}` at item `{:?}`", key.0, key.1 }
}
-
/// The list of backend features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
- query global_backend_features(_: ()) -> Vec<String> {
+ query global_backend_features(_: ()) -> &'tcx Vec<String> {
arena_cache
eval_always
desc { "computing the backend features for CLI flags" }
}
- query generator_diagnostic_data(key: DefId) -> Option<GeneratorDiagnosticData<'tcx>> {
+ query generator_diagnostic_data(key: DefId) -> &'tcx Option<GeneratorDiagnosticData<'tcx>> {
arena_cache
desc { |tcx| "looking up generator diagnostic data of `{}`", tcx.def_path_str(key) }
separate_provide_extern
($K:ty) => { $K };
}
-macro_rules! query_storage {
- ([][$K:ty, $V:ty]) => {
- <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+macro_rules! query_if_arena {
+ ([] $arena:ty, $no_arena:ty) => {
+ $no_arena
};
- ([(arena_cache) $($rest:tt)*][$K:ty, $V:ty]) => {
- <<$K as Key>::CacheSelector as CacheSelector<'tcx, $V>>::ArenaCache
+ ([(arena_cache) $($rest:tt)*] $arena:ty, $no_arena:ty) => {
+ $arena
};
- ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
- query_storage!([$($modifiers)*][$($args)*])
+ ([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
+ query_if_arena!([$($modifiers)*]$($args)*)
};
}
$(pub type $name<'tcx> = $($K)*;)*
}
- #[allow(nonstandard_style, unused_lifetimes)]
+ #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
pub mod query_values {
use super::*;
- $(pub type $name<'tcx> = $V;)*
+ $(pub type $name<'tcx> = query_if_arena!([$($modifiers)*] <$V as Deref>::Target, $V);)*
}
- #[allow(nonstandard_style, unused_lifetimes)]
+ #[allow(nonstandard_style, unused_lifetimes, unused_parens)]
pub mod query_storage {
use super::*;
- $(pub type $name<'tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
+ $(
+ pub type $name<'tcx> = query_if_arena!([$($modifiers)*]
+ <<$($K)* as Key>::CacheSelector
+ as CacheSelector<'tcx, <$V as Deref>::Target>>::ArenaCache,
+ <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, $V>>::Cache
+ );
+ )*
}
+
#[allow(nonstandard_style, unused_lifetimes)]
pub mod query_stored {
use super::*;
- $(pub type $name<'tcx> = <query_storage::$name<'tcx> as QueryStorage>::Stored;)*
+ $(pub type $name<'tcx> = $V;)*
}
#[derive(Default)]
$($(#[$attr])*
#[inline(always)]
#[must_use]
- pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
{
self.at(DUMMY_SP).$name(key)
})*
impl<'tcx> TyCtxtAt<'tcx> {
$($(#[$attr])*
#[inline(always)]
- pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<'tcx>
+ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
{
let key = key.into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
span: Span,
key: query_keys::$name<'tcx>,
mode: QueryMode,
- ) -> Option<query_stored::$name<'tcx>>;)*
+ ) -> Option<$V>;)*
}
};
}
$(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
$(#[$attr])*
#[inline(always)]
- pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
+ pub fn $name(self, value: query_values::$name<'tcx>) -> $V {
let key = self.key().into_query_param();
opt_remap_env_constness!([$($modifiers)*][key]);
use crate::elaborate_drops::DropFlagState;
-use rustc_middle::mir::{self, Body, Location};
+use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::VariantIdx;
on_all_children_bits(tcx, body, move_data, path, |mpi| callback(mpi, DropFlagState::Absent))
}
+ // Drop does not count as a move but we should still consider the variable uninitialized.
+ if let Some(Terminator { kind: TerminatorKind::Drop { place, .. }, .. }) =
+ body.stmt_at(loc).right()
+ {
+ if let LookupResult::Exact(mpi) = move_data.rev_lookup.find(place.as_ref()) {
+ on_all_children_bits(tcx, body, move_data, mpi, |mpi| {
+ callback(mpi, DropFlagState::Absent)
+ })
+ }
+ }
+
debug!("drop_flag_effects: assignment for location({:?})", loc);
for_location_inits(tcx, body, move_data, loc, |mpi| callback(mpi, DropFlagState::Present));
| TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::GeneratorDrop
- | TerminatorKind::Unreachable => {}
+ | TerminatorKind::Unreachable
+ | TerminatorKind::Drop { .. } => {}
TerminatorKind::Assert { ref cond, .. } => {
self.gather_operand(cond);
self.create_move_path(place);
self.gather_init(place.as_ref(), InitKind::Deep);
}
-
- TerminatorKind::Drop { place, target: _, unwind: _ } => {
- self.gather_move(place);
- }
TerminatorKind::DropAndReplace { place, ref value, .. } => {
self.create_move_path(place);
self.gather_operand(value);
self.super_terminator(terminator, state)
}
- fn super_terminator(&self, terminator: &Terminator<'tcx>, _state: &mut State<Self::Value>) {
+ fn super_terminator(&self, terminator: &Terminator<'tcx>, state: &mut State<Self::Value>) {
match &terminator.kind {
TerminatorKind::Call { .. } | TerminatorKind::InlineAsm { .. } => {
// Effect is applied by `handle_call_return`.
}
- TerminatorKind::Drop { .. } => {
- // We don't track dropped places.
+ TerminatorKind::Drop { place, .. } => {
+ state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
}
TerminatorKind::DropAndReplace { .. } | TerminatorKind::Yield { .. } => {
// They would have an effect, but are not allowed in this phase.
use rustc_target::abi::VariantIdx;
use std::fmt;
+/// During MIR building, Drop and DropAndReplace terminators are inserted in every place where a drop may occur.
+/// However, in this phase, the presence of these terminators does not guarantee that a destructor will run,
+/// as the target of the drop may be uninitialized.
+/// In general, the compiler cannot determine at compile time whether a destructor will run or not.
+///
+/// At a high level, this pass refines Drop and DropAndReplace to only run the destructor if the
+/// target is initialized. The way this is achievied is by inserting drop flags for every variable
+/// that may be dropped, and then using those flags to determine whether a destructor should run.
+/// This pass also removes DropAndReplace, replacing it with a Drop paired with an assign statement.
+/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
+/// "drop shim" for the type of the dropped place.
+///
+/// This pass relies on dropped places having an associated move path, which is then used to determine
+/// the initialization status of the place and its descendants.
+/// It's worth noting that a MIR containing a Drop without an associated move path is probably ill formed,
+/// as it would allow running a destructor on a place behind a reference:
+///
+/// ```text
+// fn drop_term<T>(t: &mut T) {
+// mir!(
+// {
+// Drop(*t, exit)
+// }
+// exit = {
+// Return()
+// }
+// )
+// }
+/// ```
pub struct ElaborateDrops;
impl<'tcx> MirPass<'tcx> for ElaborateDrops {
}
impl From<DepNodeIndex> for QueryInvocationId {
- #[inline]
+ #[inline(always)]
fn from(dep_node_index: DepNodeIndex) -> Self {
QueryInvocationId(dep_node_index.as_u32())
}
pub trait QueryStorage {
type Value: Debug;
type Stored: Copy;
-
- /// Store a value without putting it in the cache.
- /// This is meant to be used with cycle errors.
- fn store_nocache(&self, value: Self::Value) -> Self::Stored;
}
pub trait QueryCache: QueryStorage + Sized {
impl<K: Eq + Hash, V: Copy + Debug> QueryStorage for DefaultCache<K, V> {
type Value = V;
type Stored = V;
-
- #[inline]
- fn store_nocache(&self, value: Self::Value) -> Self::Stored {
- // We have no dedicated storage
- value
- }
}
impl<K, V> QueryCache for DefaultCache<K, V>
impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
type Value = V;
type Stored = &'tcx V;
-
- #[inline]
- fn store_nocache(&self, value: Self::Value) -> Self::Stored {
- let value = self.arena.alloc((value, DepNodeIndex::INVALID));
- let value = unsafe { &*(&value.0 as *const _) };
- &value
- }
}
impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
impl<K: Eq + Idx, V: Copy + Debug> QueryStorage for VecCache<K, V> {
type Value = V;
type Stored = V;
-
- #[inline]
- fn store_nocache(&self, value: Self::Value) -> Self::Stored {
- // We have no dedicated storage
- value
- }
}
impl<K, V> QueryCache for VecCache<K, V>
impl<'tcx, K: Eq + Idx, V: Debug + 'tcx> QueryStorage for VecArenaCache<'tcx, K, V> {
type Value = V;
type Stored = &'tcx V;
-
- #[inline]
- fn store_nocache(&self, value: Self::Value) -> Self::Stored {
- let value = self.arena.alloc((value, DepNodeIndex::INVALID));
- let value = unsafe { &*(&value.0 as *const _) };
- &value
- }
}
impl<'tcx, K, V: 'tcx> QueryCache for VecArenaCache<'tcx, K, V>
#[cold]
#[inline(never)]
-fn mk_cycle<Qcx, V, R, D: DepKind>(
+fn mk_cycle<Qcx, R, D: DepKind>(
qcx: Qcx,
cycle_error: CycleError<D>,
handler: HandleCycleError,
- cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
) -> R
where
Qcx: QueryContext + crate::query::HasDepContext<DepKind = D>,
- V: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>,
- R: Copy,
+ R: std::fmt::Debug + Value<Qcx::DepContext, Qcx::DepKind>,
{
let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
- let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler);
- cache.store_nocache(value)
+ handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler)
}
fn handle_cycle_error<Tcx, V>(
{
match cache.lookup(&key) {
Some((value, index)) => {
- if std::intrinsics::unlikely(tcx.profiler().enabled()) {
- tcx.profiler().query_cache_hit(index.into());
- }
+ tcx.profiler().query_cache_hit(index.into());
tcx.dep_graph().read_index(index);
Some(value)
}
(result, Some(dep_node_index))
}
TryGetJob::Cycle(error) => {
- let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR, cache);
+ let result = mk_cycle(qcx, error, Q::HANDLE_CYCLE_ERROR);
(result, None)
}
#[cfg(parallel_compiler)]
panic!("value must be in cache after waiting")
};
- if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
- qcx.dep_context().profiler().query_cache_hit(index.into());
- }
+ qcx.dep_context().profiler().query_cache_hit(index.into());
query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
(v, Some(index))
// Ensure that only one of them runs the query.
let cache = Q::query_cache(qcx);
if let Some((_, index)) = cache.lookup(&key) {
- if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
- qcx.dep_context().profiler().query_cache_hit(index.into());
- }
+ qcx.dep_context().profiler().query_cache_hit(index.into());
return;
}
"what location details should be tracked when using caller_location, either \
`none`, or a comma separated list of location details, for which \
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
- log_backtrace: Option<String> = (None, parse_opt_string, [TRACKED],
- "add a backtrace along with logging"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
plugins,
pointee_trait,
pointer,
- pointer_sized,
+ pointer_like,
poll,
position,
post_dash_lto: "post-lto",
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
- // A type is `PointerSized` if we can compute its layout, and that layout
+ // A type is `PointerLike` if we can compute its layout, and that layout
// matches the layout of `usize`.
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
|| lang_items.clone_trait() == Some(trait_def_id)
{
G::consider_builtin_copy_clone_candidate(self, goal)
- } else if lang_items.pointer_sized() == Some(trait_def_id) {
- G::consider_builtin_pointer_sized_candidate(self, goal)
+ } else if lang_items.pointer_like() == Some(trait_def_id) {
+ G::consider_builtin_pointer_like_candidate(self, goal)
} else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) {
G::consider_builtin_fn_trait_candidates(self, goal, kind)
} else if lang_items.tuple_trait() == Some(trait_def_id) {
)
}
ty::PredicateKind::Subtype(pred) => {
- let (a, b) = infcx.replace_bound_vars_with_placeholders(
+ let (a, b) = infcx.instantiate_binder_with_placeholders(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(true, a, b);
)
}
ty::PredicateKind::Coerce(pred) => {
- let (a, b) = infcx.replace_bound_vars_with_placeholders(
+ let (a, b) = infcx.instantiate_binder_with_placeholders(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(false, a, b);
)
}
ty::PredicateKind::ConstEquate(a, b) => {
- let (a, b) = infcx.replace_bound_vars_with_placeholders(
+ let (a, b) = infcx.instantiate_binder_with_placeholders(
goal.predicate.kind().rebind((a, b)),
);
let expected_found = ExpectedFound::new(true, a, b);
rhs: T,
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution>;
- fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
+ fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
&self,
value: ty::Binder<'tcx, T>,
) -> T;
})
}
- fn instantiate_bound_vars_with_infer<T: TypeFoldable<'tcx> + Copy>(
+ fn instantiate_binder_with_infer<T: TypeFoldable<'tcx> + Copy>(
&self,
value: ty::Binder<'tcx, T>,
) -> T {
- self.replace_bound_vars_with_fresh_vars(
+ self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
LateBoundRegionConversionTime::HigherRankedType,
value,
}
}
} else {
- let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
+ let kind = self.infcx.instantiate_binder_with_placeholders(kind);
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
let (_, certainty) = self.evaluate_goal(goal)?;
self.make_canonical_response(certainty)
{
ecx.infcx.probe(|_| {
let assumption_projection_pred =
- ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
+ ecx.infcx.instantiate_binder_with_infer(poly_projection_pred);
let nested_goals = ecx.infcx.eq(
goal.param_env,
goal.predicate.projection_ty,
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
}
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
_ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
- bug!("`PointerSized` does not have an associated type: {:?}", goal);
+ bug!("`PointerLike` does not have an associated type: {:?}", goal);
}
fn consider_builtin_fn_trait_candidates(
use overflow::OverflowData;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::TyCtxt;
-use std::collections::hash_map::Entry;
+use std::{collections::hash_map::Entry, mem};
rustc_index::newtype_index! {
pub struct StackDepth {}
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
let provisional_entry = &mut cache.entries[provisional_entry_index];
let depth = provisional_entry.depth;
+ // We eagerly update the response in the cache here. If we have to reevaluate
+ // this goal we use the new response when hitting a cycle, and we definitely
+ // want to access the final response whenever we look at the cache.
+ let prev_response = mem::replace(&mut provisional_entry.response, response);
+
// Was the current goal the root of a cycle and was the provisional response
// different from the final one.
- if has_been_used && provisional_entry.response != response {
- // If so, update the provisional reponse for this goal...
- provisional_entry.response = response;
- // ...remove all entries whose result depends on this goal
+ if has_been_used && prev_response != response {
+ // If so, remove all entries whose result depends on this goal
// from the provisional cache...
//
// That's not completely correct, as a nested goal can also
// FIXME: Constness and polarity
ecx.infcx.probe(|_| {
let assumption_trait_pred =
- ecx.infcx.instantiate_bound_vars_with_infer(poly_trait_pred);
+ ecx.infcx.instantiate_binder_with_infer(poly_trait_pred);
let nested_goals = ecx.infcx.eq(
goal.param_env,
goal.predicate.trait_ref,
)
}
- fn consider_builtin_pointer_sized_candidate(
+ fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
}
ty::GeneratorWitness(types) => {
- Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+ Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
}
ty::GeneratorWitnessMIR(..) => todo!(),
}
ty::GeneratorWitness(types) => {
- Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec())
+ Ok(infcx.instantiate_binder_with_placeholders(types).to_vec())
}
ty::GeneratorWitnessMIR(..) => todo!(),
let impl_may_apply = |impl_def_id| {
let ocx = ObligationCtxt::new_in_snapshot(infcx);
let placeholder_obligation =
- infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ infcx.instantiate_binder_with_placeholders(obligation.predicate);
let obligation_trait_ref =
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| {
let ocx = ObligationCtxt::new_in_snapshot(infcx);
let placeholder_obligation =
- infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ infcx.instantiate_binder_with_placeholders(obligation.predicate);
let obligation_trait_ref =
ocx.normalize(&ObligationCause::dummy(), param_env, placeholder_obligation.trait_ref);
- let param_env_predicate = infcx.replace_bound_vars_with_fresh_vars(
+ let param_env_predicate = infcx.instantiate_binder_with_fresh_vars(
DUMMY_SP,
LateBoundRegionConversionTime::HigherRankedType,
poly_trait_predicate,
let (values, err) = if let ty::PredicateKind::Clause(ty::Clause::Projection(data)) =
bound_predicate.skip_binder()
{
- let data = self.replace_bound_vars_with_fresh_vars(
+ let data = self.instantiate_binder_with_fresh_vars(
obligation.cause.span,
infer::LateBoundRegionConversionTime::HigherRankedType,
bound_predicate.rebind(data),
return false;
}
- let self_ty = self.replace_bound_vars_with_fresh_vars(
+ let self_ty = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
LateBoundRegionConversionTime::FnCall,
trait_pred.self_ty(),
}
}) else { return None; };
- let output = self.replace_bound_vars_with_fresh_vars(
+ let output = self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
LateBoundRegionConversionTime::FnCall,
output,
.skip_binder()
.iter()
.map(|ty| {
- self.replace_bound_vars_with_fresh_vars(
+ self.instantiate_binder_with_fresh_vars(
DUMMY_SP,
LateBoundRegionConversionTime::FnCall,
inputs.rebind(*ty),
err: &mut Diagnostic,
) {
let found_args = match found.kind() {
- ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
+ ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
}
};
let expected_args = match expected.kind() {
- ty::FnPtr(f) => infcx.replace_bound_vars_with_placeholders(*f).inputs().iter(),
+ ty::FnPtr(f) => infcx.instantiate_binder_with_placeholders(*f).inputs().iter(),
kind => {
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
}
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
let pred =
- ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
+ ty::Binder::dummy(infcx.instantiate_binder_with_placeholders(binder));
ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
}
ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
let r = infcx.commit_if_ok(|_snapshot| {
let old_universe = infcx.universe();
let placeholder_predicate =
- infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ infcx.instantiate_binder_with_placeholders(obligation.predicate);
let new_universe = infcx.universe();
let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate);
let cause = &obligation.cause;
let param_env = obligation.param_env;
- let cache_entry = infcx.replace_bound_vars_with_fresh_vars(
+ let cache_entry = infcx.instantiate_binder_with_fresh_vars(
cause.span,
LateBoundRegionConversionTime::HigherRankedType,
poly_cache_entry,
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else if lang_items.tuple_trait() == Some(def_id) {
self.assemble_candidate_for_tuple(obligation, &mut candidates);
- } else if lang_items.pointer_sized() == Some(def_id) {
+ } else if lang_items.pointer_like() == Some(def_id) {
self.assemble_candidate_for_ptr_sized(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
- self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate);
+ self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
// Count only those upcast versions that match the trait-ref
// we are looking for. Specifically, do not only check for the
let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
let placeholder_trait_predicate =
- self.infcx.replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+ self.infcx.instantiate_binder_with_placeholders(trait_predicate).trait_ref;
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
let cause = obligation.derived_cause(BuiltinDerivedObligation);
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
- let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+ let trait_ref = self.infcx.instantiate_binder_with_placeholders(poly_trait_ref);
let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
&cause,
obligation.recursion_depth + 1,
let tcx = self.tcx();
debug!(?obligation, ?index, "confirm_object_candidate");
- let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let trait_predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
let ty::Dynamic(data, ..) = *self_ty.kind() else {
let object_trait_ref = data.principal().unwrap_or_else(|| {
span_bug!(obligation.cause.span, "object candidate with no principal")
});
- let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars(
+ let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
HigherRankedType,
object_trait_ref,
}
// Confirm the `type Output: Sized;` bound that is present on `FnOnce`
- let output_ty = self.infcx.replace_bound_vars_with_placeholders(sig.output());
+ let output_ty = self.infcx.instantiate_binder_with_placeholders(sig.output());
let output_ty = normalize_with_depth_to(
self,
obligation.param_env,
debug!(?obligation, "confirm_trait_alias_candidate");
let alias_def_id = obligation.predicate.def_id();
- let predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let predicate = self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
let trait_ref = predicate.trait_ref;
let trait_def_id = trait_ref.def_id;
let substs = trait_ref.substs;
) -> smallvec::SmallVec<[(usize, ty::BoundConstness); 2]> {
let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
let placeholder_trait_predicate =
- self.infcx.replace_bound_vars_with_placeholders(poly_trait_predicate);
+ self.infcx.instantiate_binder_with_placeholders(poly_trait_predicate);
debug!(?placeholder_trait_predicate);
let tcx = self.infcx.tcx;
potentially_unnormalized_candidates: bool,
) -> ProjectionMatchesProjection {
let mut nested_obligations = Vec::new();
- let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars(
+ let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars(
obligation.cause.span,
LateBoundRegionConversionTime::HigherRankedType,
env_predicate,
.flat_map(|ty| {
let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
- let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
+ let placeholder_ty = self.infcx.instantiate_binder_with_placeholders(ty);
let Normalized { value: normalized_ty, mut obligations } =
ensure_sufficient_stack(|| {
project::normalize_with_depth(
obligation: &TraitObligation<'tcx>,
) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
let placeholder_obligation =
- self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ self.infcx.instantiate_binder_with_placeholders(obligation.predicate);
let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
// which is different from how types/const are freshened.
| TypeFlags::HAS_TY_FRESH.bits
| TypeFlags::HAS_CT_FRESH.bits
- | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+ | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits
+ | TypeFlags::HAS_RE_ERASED.bits;
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
impl<I: Interner> PartialEq for TyKind<I> {
#[inline]
fn eq(&self, other: &TyKind<I>) -> bool {
- tykind_discriminant(self) == tykind_discriminant(other)
- && match (self, other) {
- (Int(a_i), Int(b_i)) => a_i == b_i,
- (Uint(a_u), Uint(b_u)) => a_u == b_u,
- (Float(a_f), Float(b_f)) => a_f == b_f,
- (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
- (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
- (Slice(a_t), Slice(b_t)) => a_t == b_t,
- (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
- (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
- (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
- (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
- a_p == b_p && a_r == b_r && a_repr == b_repr
- }
- (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
- (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
- a_d == b_d && a_s == b_s && a_m == b_m
- }
- (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
- (
- &GeneratorWitnessMIR(ref a_d, ref a_s),
- &GeneratorWitnessMIR(ref b_d, ref b_s),
- ) => a_d == b_d && a_s == b_s,
- (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
- (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
- (Param(a_p), Param(b_p)) => a_p == b_p,
- (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
- (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
- (Infer(a_t), Infer(b_t)) => a_t == b_t,
- (Error(a_e), Error(b_e)) => a_e == b_e,
- (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
- _ => {
- debug_assert!(
- false,
- "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
- );
- true
- }
+ // You might expect this `match` to be preceded with this:
+ //
+ // tykind_discriminant(self) == tykind_discriminant(other) &&
+ //
+ // but the data patterns in practice are such that a comparison
+ // succeeds 99%+ of the time, and it's faster to omit it.
+ match (self, other) {
+ (Int(a_i), Int(b_i)) => a_i == b_i,
+ (Uint(a_u), Uint(b_u)) => a_u == b_u,
+ (Float(a_f), Float(b_f)) => a_f == b_f,
+ (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
+ (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
+ (Slice(a_t), Slice(b_t)) => a_t == b_t,
+ (RawPtr(a_t), RawPtr(b_t)) => a_t == b_t,
+ (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
+ (FnDef(a_d, a_s), FnDef(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (FnPtr(a_s), FnPtr(b_s)) => a_s == b_s,
+ (Dynamic(a_p, a_r, a_repr), Dynamic(b_p, b_r, b_repr)) => {
+ a_p == b_p && a_r == b_r && a_repr == b_repr
}
+ (Closure(a_d, a_s), Closure(b_d, b_s)) => a_d == b_d && a_s == b_s,
+ (Generator(a_d, a_s, a_m), Generator(b_d, b_s, b_m)) => {
+ a_d == b_d && a_s == b_s && a_m == b_m
+ }
+ (GeneratorWitness(a_g), GeneratorWitness(b_g)) => a_g == b_g,
+ (&GeneratorWitnessMIR(ref a_d, ref a_s), &GeneratorWitnessMIR(ref b_d, ref b_s)) => {
+ a_d == b_d && a_s == b_s
+ }
+ (Tuple(a_t), Tuple(b_t)) => a_t == b_t,
+ (Alias(a_i, a_p), Alias(b_i, b_p)) => a_i == b_i && a_p == b_p,
+ (Param(a_p), Param(b_p)) => a_p == b_p,
+ (Bound(a_d, a_b), Bound(b_d, b_b)) => a_d == b_d && a_b == b_b,
+ (Placeholder(a_p), Placeholder(b_p)) => a_p == b_p,
+ (Infer(a_t), Infer(b_t)) => a_t == b_t,
+ (Error(a_e), Error(b_e)) => a_e == b_e,
+ (Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => true,
+ _ => {
+ debug_assert!(
+ tykind_discriminant(self) != tykind_discriminant(other),
+ "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+ );
+ false
+ }
+ }
}
}
(Error(a_e), Error(b_e)) => a_e.cmp(b_e),
(Bool, Bool) | (Char, Char) | (Str, Str) | (Never, Never) => Ordering::Equal,
_ => {
- debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}");
+ debug_assert!(false, "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}");
Ordering::Equal
}
}
// SAFETY: our own safety conditions imply this reference is again unique.
unsafe { &mut *self.ptr.as_ptr() }
}
+
+ /// Borrows a new mutable reference from the unique borrow initially captured.
+ ///
+ /// # Safety
+ ///
+ /// The reborrow must have ended, i.e., the reference returned by `new` and
+ /// all pointers and references derived from it, must not be used anymore.
+ pub unsafe fn reborrow(&mut self) -> &'a mut T {
+ // SAFETY: our own safety conditions imply this reference is again unique.
+ unsafe { &mut *self.ptr.as_ptr() }
+ }
+
+ /// Borrows a new shared reference from the unique borrow initially captured.
+ ///
+ /// # Safety
+ ///
+ /// The reborrow must have ended, i.e., the reference returned by `new` and
+ /// all pointers and references derived from it, must not be used anymore.
+ pub unsafe fn reborrow_shared(&self) -> &'a T {
+ // SAFETY: our own safety conditions imply this reference is again unique.
+ unsafe { &*self.ptr.as_ptr() }
+ }
}
#[cfg(test)]
use core::iter::{FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::mem::{self, ManuallyDrop};
-use core::ops::{Index, RangeBounds};
+use core::ops::{Bound, Index, RangeBounds};
use core::ptr;
use crate::alloc::{Allocator, Global};
use super::dedup_sorted_iter::DedupSortedIter;
use super::navigate::{LazyLeafRange, LeafRange};
use super::node::{self, marker, ForceResult::*, Handle, NodeRef, Root};
-use super::search::SearchResult::*;
+use super::search::{SearchBound, SearchResult::*};
use super::set_val::SetValZST;
mod entry;
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
+
+ /// Returns a [`Cursor`] pointing at the first element that is above the
+ /// given bound.
+ ///
+ /// If no such element exists then a cursor pointing at the "ghost"
+ /// non-element is returned.
+ ///
+ /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+ /// element of the map.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_cursors)]
+ ///
+ /// use std::collections::BTreeMap;
+ /// use std::ops::Bound;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(4, "c");
+ /// let cursor = a.lower_bound(Bound::Excluded(&2));
+ /// assert_eq!(cursor.key(), Some(&3));
+ /// ```
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+ where
+ K: Borrow<Q> + Ord,
+ Q: Ord,
+ {
+ let root_node = match self.root.as_ref() {
+ None => return Cursor { current: None, root: None },
+ Some(root) => root.reborrow(),
+ };
+ let edge = root_node.lower_bound(SearchBound::from_range(bound));
+ Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() }
+ }
+
+ /// Returns a [`CursorMut`] pointing at the first element that is above the
+ /// given bound.
+ ///
+ /// If no such element exists then a cursor pointing at the "ghost"
+ /// non-element is returned.
+ ///
+ /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
+ /// element of the map.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_cursors)]
+ ///
+ /// use std::collections::BTreeMap;
+ /// use std::ops::Bound;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(4, "c");
+ /// let cursor = a.lower_bound_mut(Bound::Excluded(&2));
+ /// assert_eq!(cursor.key(), Some(&3));
+ /// ```
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn lower_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+ where
+ K: Borrow<Q> + Ord,
+ Q: Ord,
+ {
+ let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+ let root_node = match root.as_mut() {
+ None => {
+ return CursorMut {
+ current: None,
+ root: dormant_root,
+ length: &mut self.length,
+ alloc: &mut *self.alloc,
+ };
+ }
+ Some(root) => root.borrow_mut(),
+ };
+ let edge = root_node.lower_bound(SearchBound::from_range(bound));
+ CursorMut {
+ current: edge.next_kv().ok(),
+ root: dormant_root,
+ length: &mut self.length,
+ alloc: &mut *self.alloc,
+ }
+ }
+
+ /// Returns a [`Cursor`] pointing at the last element that is below the
+ /// given bound.
+ ///
+ /// If no such element exists then a cursor pointing at the "ghost"
+ /// non-element is returned.
+ ///
+ /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+ /// element of the map.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_cursors)]
+ ///
+ /// use std::collections::BTreeMap;
+ /// use std::ops::Bound;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(4, "c");
+ /// let cursor = a.upper_bound(Bound::Excluded(&3));
+ /// assert_eq!(cursor.key(), Some(&2));
+ /// ```
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+ where
+ K: Borrow<Q> + Ord,
+ Q: Ord,
+ {
+ let root_node = match self.root.as_ref() {
+ None => return Cursor { current: None, root: None },
+ Some(root) => root.reborrow(),
+ };
+ let edge = root_node.upper_bound(SearchBound::from_range(bound));
+ Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() }
+ }
+
+ /// Returns a [`CursorMut`] pointing at the last element that is below the
+ /// given bound.
+ ///
+ /// If no such element exists then a cursor pointing at the "ghost"
+ /// non-element is returned.
+ ///
+ /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
+ /// element of the map.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(btree_cursors)]
+ ///
+ /// use std::collections::BTreeMap;
+ /// use std::ops::Bound;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "a");
+ /// a.insert(2, "b");
+ /// a.insert(3, "c");
+ /// a.insert(4, "c");
+ /// let cursor = a.upper_bound_mut(Bound::Excluded(&3));
+ /// assert_eq!(cursor.key(), Some(&2));
+ /// ```
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn upper_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+ where
+ K: Borrow<Q> + Ord,
+ Q: Ord,
+ {
+ let (root, dormant_root) = DormantMutRef::new(&mut self.root);
+ let root_node = match root.as_mut() {
+ None => {
+ return CursorMut {
+ current: None,
+ root: dormant_root,
+ length: &mut self.length,
+ alloc: &mut *self.alloc,
+ };
+ }
+ Some(root) => root.borrow_mut(),
+ };
+ let edge = root_node.upper_bound(SearchBound::from_range(bound));
+ CursorMut {
+ current: edge.next_back_kv().ok(),
+ root: dormant_root,
+ length: &mut self.length,
+ alloc: &mut *self.alloc,
+ }
+ }
+}
+
+/// A cursor over a `BTreeMap`.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct Cursor<'a, K: 'a, V: 'a> {
+ current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+ root: Option<&'a node::Root<K, V>>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K, V> Clone for Cursor<'_, K, V> {
+ fn clone(&self) -> Self {
+ let Cursor { current, root } = *self;
+ Cursor { current, root }
+ }
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug> Debug for Cursor<'_, K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Cursor").field(&self.key_value()).finish()
+ }
+}
+
+/// A cursor over a `BTreeMap` with editing operations.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the tree during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying tree. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to an element in the tree, and index in a logically circular way.
+/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
+/// first elements of the tree.
+///
+/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`]
+/// methods.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMut<
+ 'a,
+ K: 'a,
+ V: 'a,
+ #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
+> {
+ current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+ root: DormantMutRef<'a, Option<node::Root<K, V>>>,
+ length: &'a mut usize,
+ alloc: &'a mut A,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("CursorMut").field(&self.key_value()).finish()
+ }
+}
+
+impl<'a, K, V> Cursor<'a, K, V> {
+ /// Moves the cursor to the next element of the `BTreeMap`.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this will move it to
+ /// the first element of the `BTreeMap`. If it is pointing to the last
+ /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn move_next(&mut self) {
+ match self.current.take() {
+ None => {
+ self.current = self.root.and_then(|root| {
+ root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok()
+ });
+ }
+ Some(current) => {
+ self.current = current.next_leaf_edge().next_kv().ok();
+ }
+ }
+ }
+
+ /// Moves the cursor to the previous element of the `BTreeMap`.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this will move it to
+ /// the last element of the `BTreeMap`. If it is pointing to the first
+ /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn move_prev(&mut self) {
+ match self.current.take() {
+ None => {
+ self.current = self.root.and_then(|root| {
+ root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok()
+ });
+ }
+ Some(current) => {
+ self.current = current.next_back_leaf_edge().next_back_kv().ok();
+ }
+ }
+ }
+
+ /// Returns a reference to the key of the element that the cursor is
+ /// currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn key(&self) -> Option<&'a K> {
+ self.current.as_ref().map(|current| current.into_kv().0)
+ }
+
+ /// Returns a reference to the value of the element that the cursor is
+ /// currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn value(&self) -> Option<&'a V> {
+ self.current.as_ref().map(|current| current.into_kv().1)
+ }
+
+ /// Returns a reference to the key and value of the element that the cursor
+ /// is currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn key_value(&self) -> Option<(&'a K, &'a V)> {
+ self.current.as_ref().map(|current| current.into_kv())
+ }
+
+ /// Returns a reference to the next element.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this returns
+ /// the first element of the `BTreeMap`. If it is pointing to the last
+ /// element of the `BTreeMap` then this returns `None`.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn peek_next(&self) -> Option<(&'a K, &'a V)> {
+ let mut next = self.clone();
+ next.move_next();
+ next.current.as_ref().map(|current| current.into_kv())
+ }
+
+ /// Returns a reference to the previous element.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this returns
+ /// the last element of the `BTreeMap`. If it is pointing to the first
+ /// element of the `BTreeMap` then this returns `None`.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> {
+ let mut prev = self.clone();
+ prev.move_prev();
+ prev.current.as_ref().map(|current| current.into_kv())
+ }
+}
+
+impl<'a, K, V, A> CursorMut<'a, K, V, A> {
+ /// Moves the cursor to the next element of the `BTreeMap`.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this will move it to
+ /// the first element of the `BTreeMap`. If it is pointing to the last
+ /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn move_next(&mut self) {
+ match self.current.take() {
+ None => {
+ // SAFETY: The previous borrow of root has ended.
+ self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+ root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok()
+ });
+ }
+ Some(current) => {
+ self.current = current.next_leaf_edge().next_kv().ok();
+ }
+ }
+ }
+
+ /// Moves the cursor to the previous element of the `BTreeMap`.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this will move it to
+ /// the last element of the `BTreeMap`. If it is pointing to the first
+ /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn move_prev(&mut self) {
+ match self.current.take() {
+ None => {
+ // SAFETY: The previous borrow of root has ended.
+ self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
+ root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok()
+ });
+ }
+ Some(current) => {
+ self.current = current.next_back_leaf_edge().next_back_kv().ok();
+ }
+ }
+ }
+
+ /// Returns a reference to the key of the element that the cursor is
+ /// currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn key(&self) -> Option<&K> {
+ self.current.as_ref().map(|current| current.reborrow().into_kv().0)
+ }
+
+ /// Returns a reference to the value of the element that the cursor is
+ /// currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn value(&self) -> Option<&V> {
+ self.current.as_ref().map(|current| current.reborrow().into_kv().1)
+ }
+
+ /// Returns a reference to the key and value of the element that the cursor
+ /// is currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn key_value(&self) -> Option<(&K, &V)> {
+ self.current.as_ref().map(|current| current.reborrow().into_kv())
+ }
+
+ /// Returns a mutable reference to the value of the element that the cursor
+ /// is currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn value_mut(&mut self) -> Option<&mut V> {
+ self.current.as_mut().map(|current| current.kv_mut().1)
+ }
+
+ /// Returns a reference to the key and mutable reference to the value of the
+ /// element that the cursor is currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> {
+ self.current.as_mut().map(|current| {
+ let (k, v) = current.kv_mut();
+ (&*k, v)
+ })
+ }
+
+ /// Returns a mutable reference to the of the element that the cursor is
+ /// currently pointing to.
+ ///
+ /// This returns `None` if the cursor is currently pointing to the
+ /// "ghost" non-element.
+ ///
+ /// # Safety
+ ///
+ /// This can be used to modify the key, but you must ensure that the
+ /// `BTreeMap` invariants are maintained. Specifically:
+ ///
+ /// * The key must remain unique within the tree.
+ /// * The key must remain in sorted order with regards to other elements in
+ /// the tree.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> {
+ self.current.as_mut().map(|current| current.kv_mut().0)
+ }
+
+ /// Returns a reference to the key and value of the next element.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this returns
+ /// the first element of the `BTreeMap`. If it is pointing to the last
+ /// element of the `BTreeMap` then this returns `None`.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn peek_next(&mut self) -> Option<(&K, &mut V)> {
+ let (k, v) = match self.current {
+ None => {
+ // SAFETY: The previous borrow of root has ended.
+ unsafe { self.root.reborrow() }
+ .as_mut()?
+ .borrow_mut()
+ .first_leaf_edge()
+ .next_kv()
+ .ok()?
+ .into_kv_valmut()
+ }
+ // SAFETY: We're not using this to mutate the tree.
+ Some(ref mut current) => {
+ unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut()
+ }
+ };
+ Some((k, v))
+ }
+
+ /// Returns a reference to the key and value of the previous element.
+ ///
+ /// If the cursor is pointing to the "ghost" non-element then this returns
+ /// the last element of the `BTreeMap`. If it is pointing to the first
+ /// element of the `BTreeMap` then this returns `None`.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> {
+ let (k, v) = match self.current.as_mut() {
+ None => {
+ // SAFETY: The previous borrow of root has ended.
+ unsafe { self.root.reborrow() }
+ .as_mut()?
+ .borrow_mut()
+ .first_leaf_edge()
+ .next_kv()
+ .ok()?
+ .into_kv_valmut()
+ }
+ Some(current) => {
+ // SAFETY: We're not using this to mutate the tree.
+ unsafe { current.reborrow_mut() }
+ .next_back_leaf_edge()
+ .next_back_kv()
+ .ok()?
+ .into_kv_valmut()
+ }
+ };
+ Some((k, v))
+ }
+
+ /// Returns a read-only cursor pointing to the current element.
+ ///
+ /// The lifetime of the returned `Cursor` is bound to that of the
+ /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+ /// `CursorMut` is frozen for the lifetime of the `Cursor`.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn as_cursor(&self) -> Cursor<'_, K, V> {
+ Cursor {
+ // SAFETY: The tree is immutable while the cursor exists.
+ root: unsafe { self.root.reborrow_shared().as_ref() },
+ current: self.current.as_ref().map(|current| current.reborrow()),
+ }
+ }
+}
+
+// Now the tree editing operations
+impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
+ /// Inserts a new element into the `BTreeMap` after the current one.
+ ///
+ /// If the cursor is pointing at the "ghost" non-element then the new element is
+ /// inserted at the front of the `BTreeMap`.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure that the `BTreeMap` invariants are maintained.
+ /// Specifically:
+ ///
+ /// * The key of the newly inserted element must be unique in the tree.
+ /// * All keys in the tree must remain in sorted order.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) {
+ let edge = match self.current.take() {
+ None => {
+ // SAFETY: We have no other reference to the tree.
+ match unsafe { self.root.reborrow() } {
+ root @ None => {
+ // Tree is empty, allocate a new root.
+ let mut node = NodeRef::new_leaf(self.alloc.clone());
+ node.borrow_mut().push(key, value);
+ *root = Some(node.forget_type());
+ *self.length += 1;
+ return;
+ }
+ Some(root) => root.borrow_mut().first_leaf_edge(),
+ }
+ }
+ Some(current) => current.next_leaf_edge(),
+ };
+
+ let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+ drop(ins.left);
+ // SAFETY: The handle to the newly inserted value is always on a
+ // leaf node, so adding a new root node doesn't invalidate it.
+ let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+ root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+ });
+ self.current = handle.left_edge().next_back_kv().ok();
+ *self.length += 1;
+ }
+
+ /// Inserts a new element into the `BTreeMap` before the current one.
+ ///
+ /// If the cursor is pointing at the "ghost" non-element then the new element is
+ /// inserted at the end of the `BTreeMap`.
+ ///
+ /// # Safety
+ ///
+ /// You must ensure that the `BTreeMap` invariants are maintained.
+ /// Specifically:
+ ///
+ /// * The key of the newly inserted element must be unique in the tree.
+ /// * All keys in the tree must remain in sorted order.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) {
+ let edge = match self.current.take() {
+ None => {
+ // SAFETY: We have no other reference to the tree.
+ match unsafe { self.root.reborrow() } {
+ root @ None => {
+ // Tree is empty, allocate a new root.
+ let mut node = NodeRef::new_leaf(self.alloc.clone());
+ node.borrow_mut().push(key, value);
+ *root = Some(node.forget_type());
+ *self.length += 1;
+ return;
+ }
+ Some(root) => root.borrow_mut().last_leaf_edge(),
+ }
+ }
+ Some(current) => current.next_back_leaf_edge(),
+ };
+
+ let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
+ drop(ins.left);
+ // SAFETY: The handle to the newly inserted value is always on a
+ // leaf node, so adding a new root node doesn't invalidate it.
+ let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+ root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
+ });
+ self.current = handle.right_edge().next_kv().ok();
+ *self.length += 1;
+ }
+
+ /// Inserts a new element into the `BTreeMap` after the current one.
+ ///
+ /// If the cursor is pointing at the "ghost" non-element then the new element is
+ /// inserted at the front of the `BTreeMap`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ /// - the given key compares less than or equal to the current element (if
+ /// any).
+ /// - the given key compares greater than or equal to the next element (if
+ /// any).
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn insert_after(&mut self, key: K, value: V) {
+ if let Some(current) = self.key() {
+ if &key <= current {
+ panic!("key must be ordered above the current element");
+ }
+ }
+ if let Some((next, _)) = self.peek_prev() {
+ if &key >= next {
+ panic!("key must be ordered below the next element");
+ }
+ }
+ unsafe {
+ self.insert_after_unchecked(key, value);
+ }
+ }
+
+ /// Inserts a new element into the `BTreeMap` before the current one.
+ ///
+ /// If the cursor is pointing at the "ghost" non-element then the new element is
+ /// inserted at the end of the `BTreeMap`.
+ ///
+ /// # Panics
+ ///
+ /// This function panics if:
+ /// - the given key compares greater than or equal to the current element
+ /// (if any).
+ /// - the given key compares less than or equal to the previous element (if
+ /// any).
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn insert_before(&mut self, key: K, value: V) {
+ if let Some(current) = self.key() {
+ if &key >= current {
+ panic!("key must be ordered below the current element");
+ }
+ }
+ if let Some((prev, _)) = self.peek_prev() {
+ if &key <= prev {
+ panic!("key must be ordered above the previous element");
+ }
+ }
+ unsafe {
+ self.insert_before_unchecked(key, value);
+ }
+ }
+
+ /// Removes the current element from the `BTreeMap`.
+ ///
+ /// The element that was removed is returned, and the cursor is
+ /// moved to point to the next element in the `BTreeMap`.
+ ///
+ /// If the cursor is currently pointing to the "ghost" non-element then no element
+ /// is removed and `None` is returned. The cursor is not moved in this case.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn remove_current(&mut self) -> Option<(K, V)> {
+ let current = self.current.take()?;
+ let mut emptied_internal_root = false;
+ let (kv, pos) =
+ current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+ self.current = pos.next_kv().ok();
+ *self.length -= 1;
+ if emptied_internal_root {
+ // SAFETY: This is safe since current does not point within the now
+ // empty root node.
+ let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+ root.pop_internal_level(self.alloc.clone());
+ }
+ Some(kv)
+ }
+
+ /// Removes the current element from the `BTreeMap`.
+ ///
+ /// The element that was removed is returned, and the cursor is
+ /// moved to point to the previous element in the `BTreeMap`.
+ ///
+ /// If the cursor is currently pointing to the "ghost" non-element then no element
+ /// is removed and `None` is returned. The cursor is not moved in this case.
+ #[unstable(feature = "btree_cursors", issue = "107540")]
+ pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> {
+ let current = self.current.take()?;
+ let mut emptied_internal_root = false;
+ let (kv, pos) =
+ current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+ self.current = pos.next_back_kv().ok();
+ *self.length -= 1;
+ if emptied_internal_root {
+ // SAFETY: This is safe since current does not point within the now
+ // empty root node.
+ let root = unsafe { self.root.reborrow().as_mut().unwrap() };
+ root.pop_internal_level(self.alloc.clone());
+ }
+ Some(kv)
+ }
}
#[cfg(test)]
/// assert_eq!(map["poneyland"], 37);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn insert(self, value: V) -> &'a mut V {
+ pub fn insert(mut self, value: V) -> &'a mut V {
let out_ptr = match self.handle {
None => {
// SAFETY: There is no tree yet so no reference to it exists.
map.length = 1;
val_ptr
}
- Some(handle) => match handle.insert_recursing(self.key, value, self.alloc.clone()) {
- (None, val_ptr) => {
- // SAFETY: We have consumed self.handle.
- let map = unsafe { self.dormant_map.awaken() };
- map.length += 1;
- val_ptr
- }
- (Some(ins), val_ptr) => {
- drop(ins.left);
- // SAFETY: We have consumed self.handle and dropped the
- // remaining reference to the tree, ins.left.
- let map = unsafe { self.dormant_map.awaken() };
- let root = map.root.as_mut().unwrap(); // same as ins.left
- root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right);
- map.length += 1;
- val_ptr
- }
- },
+ Some(handle) => {
+ let new_handle =
+ handle.insert_recursing(self.key, value, self.alloc.clone(), |ins| {
+ drop(ins.left);
+ // SAFETY: Pushing a new root node doesn't invalidate
+ // handles to existing nodes.
+ let map = unsafe { self.dormant_map.reborrow() };
+ let root = map.root.as_mut().unwrap(); // same as ins.left
+ root.push_internal_level(self.alloc).push(ins.kv.0, ins.kv.1, ins.right)
+ });
+
+ // Get the pointer to the value
+ let val_ptr = new_handle.into_val_mut();
+
+ // SAFETY: We have consumed self.handle.
+ let map = unsafe { self.dormant_map.awaken() };
+ map.length += 1;
+ val_ptr
+ }
};
+
// Now that we have finished growing the tree using borrowed references,
// dereference the pointer to a part of it, that we picked up along the way.
unsafe { &mut *out_ptr }
let unordered_duplicates = BTreeMap::from([(3, 4), (1, 2), (1, 2)]);
assert_eq!(map, unordered_duplicates);
}
+
+#[test]
+fn test_cursor() {
+ let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
+
+ let mut cur = map.lower_bound(Bound::Unbounded);
+ assert_eq!(cur.key(), Some(&1));
+ cur.move_next();
+ assert_eq!(cur.key(), Some(&2));
+ assert_eq!(cur.peek_next(), Some((&3, &'c')));
+ cur.move_prev();
+ assert_eq!(cur.key(), Some(&1));
+ assert_eq!(cur.peek_prev(), None);
+
+ let mut cur = map.upper_bound(Bound::Excluded(&1));
+ assert_eq!(cur.key(), None);
+ cur.move_next();
+ assert_eq!(cur.key(), Some(&1));
+ cur.move_prev();
+ assert_eq!(cur.key(), None);
+ assert_eq!(cur.peek_prev(), Some((&3, &'c')));
+}
+
+#[test]
+fn test_cursor_mut() {
+ let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
+ let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
+ assert_eq!(cur.key(), Some(&5));
+ cur.insert_before(4, 'd');
+ assert_eq!(cur.key(), Some(&5));
+ assert_eq!(cur.peek_prev(), Some((&4, &mut 'd')));
+ cur.move_next();
+ assert_eq!(cur.key(), None);
+ cur.insert_before(6, 'f');
+ assert_eq!(cur.key(), None);
+ assert_eq!(cur.remove_current(), None);
+ assert_eq!(cur.key(), None);
+ cur.insert_after(0, '?');
+ assert_eq!(cur.key(), None);
+ assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')]));
+
+ let mut cur = map.upper_bound_mut(Bound::Included(&5));
+ assert_eq!(cur.key(), Some(&5));
+ assert_eq!(cur.remove_current(), Some((5, 'e')));
+ assert_eq!(cur.key(), Some(&6));
+ assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f')));
+ assert_eq!(cur.key(), Some(&4));
+ assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')]));
+}
use core::ptr;
use super::node::{marker, ForceResult::*, Handle, NodeRef};
+use super::search::SearchBound;
use crate::alloc::Allocator;
// `front` and `back` are always both `None` or both `Some`.
/// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV
/// on the left side, which is either in the same leaf node or in an ancestor node.
/// If the leaf edge is the first one in the tree, returns [`Result::Err`] with the root node.
- fn next_back_kv(
+ pub fn next_back_kv(
self,
) -> Result<
Handle<NodeRef<BorrowType, K, V, marker::LeafOrInternal>, marker::KV>,
}
/// Returns the leaf edge closest to a KV for backward navigation.
- fn next_back_leaf_edge(self) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
+ pub fn next_back_leaf_edge(
+ self,
+ ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge> {
match self.force() {
Leaf(leaf_kv) => leaf_kv.left_edge(),
Internal(internal_kv) => {
}
}
}
+
+impl<BorrowType: marker::BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
+ /// Returns the leaf edge corresponding to the first point at which the
+ /// given bound is true.
+ pub fn lower_bound<Q: ?Sized>(
+ self,
+ mut bound: SearchBound<&Q>,
+ ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+ where
+ Q: Ord,
+ K: Borrow<Q>,
+ {
+ let mut node = self;
+ loop {
+ let (edge, new_bound) = node.find_lower_bound_edge(bound);
+ match edge.force() {
+ Leaf(edge) => return edge,
+ Internal(edge) => {
+ node = edge.descend();
+ bound = new_bound;
+ }
+ }
+ }
+ }
+
+ /// Returns the leaf edge corresponding to the last point at which the
+ /// given bound is true.
+ pub fn upper_bound<Q: ?Sized>(
+ self,
+ mut bound: SearchBound<&Q>,
+ ) -> Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>
+ where
+ Q: Ord,
+ K: Borrow<Q>,
+ {
+ let mut node = self;
+ loop {
+ let (edge, new_bound) = node.find_upper_bound_edge(bound);
+ match edge.force() {
+ Leaf(edge) => return edge,
+ Internal(edge) => {
+ node = edge.descend();
+ bound = new_bound;
+ }
+ }
+ }
+ }
+}
// SAFETY: we have exclusive access to the entire node.
unsafe { &mut *ptr }
}
+
+ /// Returns a dormant copy of this node with its lifetime erased which can
+ /// be reawakened later.
+ pub fn dormant(&self) -> NodeRef<marker::DormantMut, K, V, Type> {
+ NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+ }
+}
+
+impl<K, V, Type> NodeRef<marker::DormantMut, K, V, Type> {
+ /// Revert to the unique borrow initially captured.
+ ///
+ /// # Safety
+ ///
+ /// The reborrow must have ended, i.e., the reference returned by `new` and
+ /// all pointers and references derived from it, must not be used anymore.
+ pub unsafe fn awaken<'a>(self) -> NodeRef<marker::Mut<'a>, K, V, Type> {
+ NodeRef { height: self.height, node: self.node, _marker: PhantomData }
+ }
}
impl<K, V, Type> NodeRef<marker::Dying, K, V, Type> {
// We can't use Handle::new_kv or Handle::new_edge because we don't know our type
Handle { node: unsafe { self.node.reborrow_mut() }, idx: self.idx, _marker: PhantomData }
}
+
+ /// Returns a dormant copy of this handle which can be reawakened later.
+ ///
+ /// See `DormantMutRef` for more details.
+ pub fn dormant(&self) -> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+ Handle { node: self.node.dormant(), idx: self.idx, _marker: PhantomData }
+ }
+}
+
+impl<K, V, NodeType, HandleType> Handle<NodeRef<marker::DormantMut, K, V, NodeType>, HandleType> {
+ /// Revert to the unique borrow initially captured.
+ ///
+ /// # Safety
+ ///
+ /// The reborrow must have ended, i.e., the reference returned by `new` and
+ /// all pointers and references derived from it, must not be used anymore.
+ pub unsafe fn awaken<'a>(self) -> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, HandleType> {
+ Handle { node: unsafe { self.node.awaken() }, idx: self.idx, _marker: PhantomData }
+ }
}
impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, marker::Edge> {
/// Inserts a new key-value pair between the key-value pairs to the right and left of
/// this edge. This method assumes that there is enough space in the node for the new
/// pair to fit.
- ///
- /// The returned pointer points to the inserted value.
- fn insert_fit(&mut self, key: K, val: V) -> *mut V {
+ unsafe fn insert_fit(
+ mut self,
+ key: K,
+ val: V,
+ ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
debug_assert!(self.node.len() < CAPACITY);
let new_len = self.node.len() + 1;
slice_insert(self.node.val_area_mut(..new_len), self.idx, val);
*self.node.len_mut() = new_len as u16;
- self.node.val_area_mut(self.idx).assume_init_mut()
+ Handle::new_kv(self.node, self.idx)
}
}
}
/// Inserts a new key-value pair between the key-value pairs to the right and left of
/// this edge. This method splits the node if there isn't enough room.
///
- /// The returned pointer points to the inserted value.
+ /// Returns a dormant handle to the inserted node which can be reawakened
+ /// once splitting is complete.
fn insert<A: Allocator + Clone>(
- mut self,
+ self,
key: K,
val: V,
alloc: A,
- ) -> (Option<SplitResult<'a, K, V, marker::Leaf>>, *mut V) {
+ ) -> (
+ Option<SplitResult<'a, K, V, marker::Leaf>>,
+ Handle<NodeRef<marker::DormantMut, K, V, marker::Leaf>, marker::KV>,
+ ) {
if self.node.len() < CAPACITY {
- let val_ptr = self.insert_fit(key, val);
- (None, val_ptr)
+ // SAFETY: There is enough space in the node for insertion.
+ let handle = unsafe { self.insert_fit(key, val) };
+ (None, handle.dormant())
} else {
let (middle_kv_idx, insertion) = splitpoint(self.idx);
let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) };
let mut result = middle.split(alloc);
- let mut insertion_edge = match insertion {
+ let insertion_edge = match insertion {
LeftOrRight::Left(insert_idx) => unsafe {
Handle::new_edge(result.left.reborrow_mut(), insert_idx)
},
Handle::new_edge(result.right.borrow_mut(), insert_idx)
},
};
- let val_ptr = insertion_edge.insert_fit(key, val);
- (Some(result), val_ptr)
+ // SAFETY: We just split the node, so there is enough space for
+ // insertion.
+ let handle = unsafe { insertion_edge.insert_fit(key, val).dormant() };
+ (Some(result), handle)
}
}
}
key: K,
value: V,
alloc: A,
- ) -> (Option<SplitResult<'a, K, V, marker::LeafOrInternal>>, *mut V) {
- let (mut split, val_ptr) = match self.insert(key, value, alloc.clone()) {
- (None, val_ptr) => return (None, val_ptr),
- (Some(split), val_ptr) => (split.forget_node_type(), val_ptr),
+ split_root: impl FnOnce(SplitResult<'a, K, V, marker::LeafOrInternal>),
+ ) -> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> {
+ let (mut split, handle) = match self.insert(key, value, alloc.clone()) {
+ // SAFETY: we have finished splitting and can now re-awaken the
+ // handle to the inserted element.
+ (None, handle) => return unsafe { handle.awaken() },
+ (Some(split), handle) => (split.forget_node_type(), handle),
};
loop {
split = match split.left.ascend() {
Ok(parent) => {
match parent.insert(split.kv.0, split.kv.1, split.right, alloc.clone()) {
- None => return (None, val_ptr),
+ // SAFETY: we have finished splitting and can now re-awaken the
+ // handle to the inserted element.
+ None => return unsafe { handle.awaken() },
Some(split) => split.forget_node_type(),
}
}
- Err(root) => return (Some(SplitResult { left: root, ..split }), val_ptr),
+ Err(root) => {
+ split_root(SplitResult { left: root, ..split });
+ // SAFETY: we have finished splitting and can now re-awaken the
+ // handle to the inserted element.
+ return unsafe { handle.awaken() };
+ }
};
}
}
let leaf = self.node.into_leaf_mut();
unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
}
+
+ pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
+ debug_assert!(self.idx < self.node.len());
+ let leaf = self.node.into_leaf_mut();
+ let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
+ let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
+ (k, v)
+ }
}
impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, marker::KV> {
pub enum Owned {}
pub enum Dying {}
+ pub enum DormantMut {}
pub struct Immut<'a>(PhantomData<&'a ()>);
pub struct Mut<'a>(PhantomData<&'a mut ()>);
pub struct ValMut<'a>(PhantomData<&'a mut ()>);
impl<'a> BorrowType for Immut<'a> {}
impl<'a> BorrowType for Mut<'a> {}
impl<'a> BorrowType for ValMut<'a> {}
+ impl BorrowType for DormantMut {}
pub enum KV {}
pub enum Edge {}
#![feature(const_eval_select)]
#![feature(const_pin)]
#![feature(const_waker)]
-#![feature(cstr_from_bytes_until_nul)]
#![feature(dispatch_from_dyn)]
#![feature(error_generic_member_access)]
#![feature(error_in_core)]
/// Copies elements from `src` range to the end of the string.
///
- /// ## Panics
+ /// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// boundary, or if they're out of bounds.
///
- /// ## Examples
+ /// # Examples
///
/// ```
/// #![feature(string_extend_from_within)]
}
}
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
impl Error for crate::ffi::FromBytesUntilNulError {}
#[unstable(feature = "get_many_mut", issue = "104642")]
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
///
#[derive(Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
pub struct FromBytesUntilNulError(());
-#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Display for FromBytesUntilNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "data provided does not contain a nul")
///
/// # Examples
/// ```
- /// #![feature(cstr_from_bytes_until_nul)]
- ///
/// use std::ffi::CStr;
///
/// let mut buffer = [0u8; 16];
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
/// ```
///
- #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
- #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+ #[rustc_allow_const_fn_unstable(const_slice_index)]
+ #[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
pub trait Tuple {}
/// A marker for things
-#[unstable(feature = "pointer_sized_trait", issue = "none")]
-#[lang = "pointer_sized"]
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+#[cfg_attr(bootstrap, lang = "pointer_sized")]
+#[cfg_attr(not(bootstrap), lang = "pointer_like")]
#[rustc_on_unimplemented(
- message = "`{Self}` needs to be a pointer-sized type",
- label = "`{Self}` needs to be a pointer-sized type"
+ message = "`{Self}` needs to have the same alignment and size as a pointer",
+ label = "`{Self}` needs to be a pointer-like type"
)]
-pub trait PointerSized {}
+pub trait PointerLike {}
/// Implementations of `Copy` for primitive types.
///
/// bytes where the borrow propagated all the way to the most significant
/// bit."
#[inline]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
const fn contains_zero_byte(x: usize) -> bool {
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
}
-#[cfg(target_pointer_width = "16")]
#[inline]
+#[cfg(target_pointer_width = "16")]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
const fn repeat_byte(b: u8) -> usize {
(b as usize) << 8 | b as usize
}
-#[cfg(not(target_pointer_width = "16"))]
#[inline]
+#[cfg(not(target_pointer_width = "16"))]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
const fn repeat_byte(b: u8) -> usize {
(b as usize) * (usize::MAX / 255)
}
/// Returns the first index matching the byte `x` in `text`.
-#[must_use]
#[inline]
+#[must_use]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices.
if text.len() < 2 * USIZE_BYTES {
}
#[inline]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
let mut i = 0;
None
}
+#[rustc_allow_const_fn_unstable(const_cmp)]
+#[rustc_allow_const_fn_unstable(const_slice_index)]
+#[rustc_allow_const_fn_unstable(const_align_offset)]
+#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
/// portability.
///
/// [`into`]: Into::into
-#[unstable(feature = "raw_os_error_ty", issue = "none")]
+#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub type RawOsError = i32;
// `#[repr(align(4))]` is probably redundant, it should have that value or
#[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
pub use self::buffered::WriterPanicked;
-#[unstable(feature = "raw_os_error_ty", issue = "none")]
+#[unstable(feature = "raw_os_error_ty", issue = "107792")]
pub use self::error::RawOsError;
pub(crate) use self::stdio::attempt_print_to_stderr;
#[unstable(feature = "internal_output_capture", issue = "none")]
#![feature(char_error_internals)]
#![feature(char_internals)]
#![feature(core_intrinsics)]
-#![feature(cstr_from_bytes_until_nul)]
#![feature(cstr_internals)]
#![feature(duration_constants)]
#![feature(error_generic_member_access)]
}
}
+#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+impl<T: AsFd> AsFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
#[stable(feature = "asfd_ptrs", since = "1.64.0")]
impl<T: AsFd> AsFd for Box<T> {
#[inline]
}
}
+#[stable(feature = "asfd_rc", since = "CURRENT_RUSTC_VERSION")]
+impl<T: AsRawFd> AsRawFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ (**self).as_raw_fd()
+ }
+}
+
#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
impl<T: AsRawFd> AsRawFd for Box<T> {
#[inline]
# If curl is not present on Win32, we should not sys.exit
# but raise `CalledProcessError` or `OSError` instead
require(["curl", "--version"], exception=platform_is_win32)
- run(["curl", option,
- "-L", # Follow redirect.
- "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds
- "--connect-timeout", "30", # timeout if cannot connect within 30 seconds
- "--retry", "3", "-Sf", "-o", path, url],
- verbose=verbose,
- exception=True, # Will raise RuntimeError on failure
- )
+ with open(path, "wb") as outfile:
+ run(["curl", option,
+ "-L", # Follow redirect.
+ "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds
+ "--connect-timeout", "30", # timeout if cannot connect within 30 seconds
+ "--retry", "3", "-Sf", url],
+ stdout=outfile, #Implements cli redirect operator '>'
+ verbose=verbose,
+ exception=True, # Will raise RuntimeError on failure
+ )
except (subprocess.CalledProcessError, OSError, RuntimeError):
# see http://serverfault.com/questions/301128/how-to-download
if platform_is_win32:
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
use crate::Config;
use crate::{t, VERSION};
+use sha2::Digest;
use std::env::consts::EXE_SUFFIX;
use std::fmt::Write as _;
use std::fs::File;
use std::str::FromStr;
use std::{fmt, fs, io};
+#[cfg(test)]
+mod tests;
+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Profile {
Compiler,
User,
}
+/// A list of historical hashes of `src/etc/vscode_settings.json`.
+/// New entries should be appended whenever this is updated so we can detected
+/// outdated vs. user-modified settings files.
+static SETTINGS_HASHES: &[&str] =
+ &["ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8"];
+static VSCODE_SETTINGS: &str = include_str!("../etc/vscode_settings.json");
+
impl Profile {
fn include_path(&self, src_path: &Path) -> PathBuf {
PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
if !config.dry_run() {
t!(install_git_hook_maybe(&config));
+ t!(create_vscode_settings_maybe(&config));
}
println!();
Ok(template)
}
+#[derive(PartialEq)]
+enum PromptResult {
+ Yes, // y/Y/yes
+ No, // n/N/no
+ Print, // p/P/print
+}
+
+/// Prompt a user for a answer, looping until they enter an accepted input or nothing
+fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> {
+ let mut input = String::new();
+ loop {
+ print!("{prompt} ");
+ io::stdout().flush()?;
+ input.clear();
+ io::stdin().read_line(&mut input)?;
+ match input.trim().to_lowercase().as_str() {
+ "y" | "yes" => return Ok(Some(PromptResult::Yes)),
+ "n" | "no" => return Ok(Some(PromptResult::No)),
+ "p" | "print" => return Ok(Some(PromptResult::Print)),
+ "" => return Ok(None),
+ _ => {
+ eprintln!("error: unrecognized option '{}'", input.trim());
+ eprintln!("note: press Ctrl+C to exit");
+ }
+ };
+ }
+}
+
// install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
return Ok(());
}
- let mut input = String::new();
- println!();
println!(
- "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
+ "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
pushing your code to ensure your code is up to par. If you decide later that this behavior is
undesirable, simply delete the `pre-push` file from .git/hooks."
);
- let should_install = loop {
- print!("Would you like to install the git hook?: [y/N] ");
- io::stdout().flush()?;
- input.clear();
- io::stdin().read_line(&mut input)?;
- break match input.trim().to_lowercase().as_str() {
- "y" | "yes" => true,
- "n" | "no" | "" => false,
- _ => {
- eprintln!("error: unrecognized option '{}'", input.trim());
- eprintln!("note: press Ctrl+C to exit");
- continue;
- }
- };
- };
-
- if should_install {
- let src = config.src.join("src").join("etc").join("pre-push.sh");
- match fs::hard_link(src, &dst) {
- Err(e) => eprintln!(
+ if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) {
+ println!("Ok, skipping installation!");
+ return Ok(());
+ }
+ let src = config.src.join("src").join("etc").join("pre-push.sh");
+ match fs::hard_link(src, &dst) {
+ Err(e) => {
+ eprintln!(
"error: could not create hook {}: do you already have the git hook installed?\n{}",
dst.display(),
e
- ),
- Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+ );
+ return Err(e);
+ }
+ Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"),
+ };
+ Ok(())
+}
+
+/// Create a `.vscode/settings.json` file for rustc development, or just print it
+fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
+ let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap();
+ let vscode_settings = config.src.join(".vscode").join("settings.json");
+ // If None, no settings.json exists
+ // If Some(true), is a previous version of settings.json
+ // If Some(false), is not a previous version (i.e. user modified)
+ // If it's up to date we can just skip this
+ let mut mismatched_settings = None;
+ if let Ok(current) = fs::read_to_string(&vscode_settings) {
+ let mut hasher = sha2::Sha256::new();
+ hasher.update(¤t);
+ let hash = hex::encode(hasher.finalize().as_slice());
+ if hash == *current_hash {
+ return Ok(());
+ } else if historical_hashes.contains(&hash.as_str()) {
+ mismatched_settings = Some(true);
+ } else {
+ mismatched_settings = Some(false);
+ }
+ }
+ println!(
+ "\nx.py can automatically install the recommended `.vscode/settings.json` file for rustc development"
+ );
+ match mismatched_settings {
+ Some(true) => eprintln!(
+ "warning: existing `.vscode/settings.json` is out of date, x.py will update it"
+ ),
+ Some(false) => eprintln!(
+ "warning: existing `.vscode/settings.json` has been modified by user, x.py will back it up and replace it"
+ ),
+ _ => (),
+ }
+ let should_create = match prompt_user(
+ "Would you like to create/update `settings.json`, or only print suggested settings?: [y/p/N]",
+ )? {
+ Some(PromptResult::Yes) => true,
+ Some(PromptResult::Print) => false,
+ _ => {
+ println!("Ok, skipping settings!");
+ return Ok(());
+ }
+ };
+ if should_create {
+ let path = config.src.join(".vscode");
+ if !path.exists() {
+ fs::create_dir(&path)?;
+ }
+ let verb = match mismatched_settings {
+ // exists but outdated, we can replace this
+ Some(true) => "Updated",
+ // exists but user modified, back it up
+ Some(false) => {
+ // exists and is not current version or outdated, so back it up
+ let mut backup = vscode_settings.clone();
+ backup.set_extension("bak");
+ eprintln!("warning: copying `settings.json` to `settings.json.bak`");
+ fs::copy(&vscode_settings, &backup)?;
+ "Updated"
+ }
+ _ => "Created",
};
+ fs::write(&vscode_settings, &VSCODE_SETTINGS)?;
+ println!("{verb} `.vscode/settings.json`");
} else {
- println!("Ok, skipping installation!");
+ println!("\n{VSCODE_SETTINGS}");
}
Ok(())
}
--- /dev/null
+use super::{SETTINGS_HASHES, VSCODE_SETTINGS};
+use sha2::Digest;
+
+#[test]
+fn check_matching_settings_hash() {
+ let mut hasher = sha2::Sha256::new();
+ hasher.update(&VSCODE_SETTINGS);
+ let hash = hex::encode(hasher.finalize().as_slice());
+ assert_eq!(
+ &hash,
+ SETTINGS_HASHES.last().unwrap(),
+ "Update `SETTINGS_HASHES` with the new hash of `src/etc/vscode_settings.json`"
+ );
+}
[output.html]
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustc"
+edit-url-template = "https://github.com/rust-lang/rust/edit/master/src/doc/rustc/{path}"
* `v0` — The "v0" mangling scheme. The specific format is not specified at
this time.
-The default if not specified will use a compiler-chosen default which may
+The default, if not specified, will use a compiler-chosen default which may
change in the future.
[name mangling]: https://en.wikipedia.org/wiki/Name_mangling
--- /dev/null
+{
+ "rust-analyzer.checkOnSave.overrideCommand": [
+ "python3",
+ "x.py",
+ "check",
+ "--json-output"
+ ],
+ "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
+ "rust-analyzer.rustfmt.overrideCommand": [
+ "./build/host/rustfmt/bin/rustfmt",
+ "--edition=2021"
+ ],
+ "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+ "rust-analyzer.procMacro.enable": true,
+ "rust-analyzer.cargo.buildScripts.enable": true,
+ "rust-analyzer.cargo.buildScripts.invocationLocation": "root",
+ "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
+ "rust-analyzer.cargo.buildScripts.overrideCommand": [
+ "python3",
+ "x.py",
+ "check",
+ "--json-output"
+ ],
+ "rust-analyzer.cargo.sysroot": "./build/host/stage0-sysroot",
+ "rust-analyzer.rustc.source": "./Cargo.toml"
+}
if f.alternate() {
f.write_str(" ")?;
} else {
- f.write_str("<br>")?;
+ f.write_str("\n")?;
}
match pred {
}
} else {
let mut br_with_padding = String::with_capacity(6 * indent + 28);
- br_with_padding.push_str("<br>");
+ br_with_padding.push_str("\n");
let padding_amout =
if ending == Ending::Newline { indent + 4 } else { indent + "fn where ".len() };
for _ in 0..padding_amout {
br_with_padding.push_str(" ");
}
- let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
+ let where_preds = where_preds.to_string().replace("\n", &br_with_padding);
if ending == Ending::Newline {
let mut clause = " ".repeat(indent.saturating_sub(1));
write!(clause, "<span class=\"where fmt-newline\">where{where_preds},</span>")?;
clause
} else {
- // insert a <br> tag after a single space but before multiple spaces at the start
+ // insert a newline after a single space but before multiple spaces at the start
if indent == 0 {
- format!("<br><span class=\"where\">where{where_preds}</span>")
+ format!("\n<span class=\"where\">where{where_preds}</span>")
} else {
// put the first one on the same line as the 'where' keyword
let where_preds = where_preds.replacen(&br_with_padding, " ", 1);
/// * `header_len`: The length of the function header and name. In other words, the number of
/// characters in the function declaration up to but not including the parentheses.
- /// <br>Used to determine line-wrapping.
+ /// This is expected to go into a `<pre>`/`code-header` block, so indentation and newlines
+ /// are preserved.
/// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
/// necessary.
pub(crate) fn full_print<'a, 'tcx: 'a>(
}
} else {
if i > 0 {
- args.push_str("<br>");
+ args.push_str("\n");
}
if input.is_const {
args.push_str("const ");
let mut args = args.into_inner();
if self.c_variadic {
- args.push_str(",<br> ...");
+ args.push_str(",\n ...");
args_plain.push_str(", ...");
}
let declaration_len = header_len + args_plain.len() + arrow_plain.len();
let output = if declaration_len > 80 {
- let full_pad = format!("<br>{}", " ".repeat(indent + 4));
- let close_pad = format!("<br>{}", " ".repeat(indent));
+ let full_pad = format!("\n{}", " ".repeat(indent + 4));
+ let close_pad = format!("\n{}", " ".repeat(indent));
format!(
"({pad}{args}{close}){arrow}",
pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
- args = args.replace("<br>", &full_pad),
+ args = args.replace("\n", &full_pad),
close = close_pad,
arrow = arrow
)
} else {
- format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
+ format!("({args}){arrow}", args = args.replace("\n", " "), arrow = arrow)
};
- if f.alternate() {
- write!(f, "{}", output.replace("<br>", "\n"))
- } else {
- write!(f, "{}", output)
- }
+ write!(f, "{}", output)
}
}
fn after_krate(&mut self) -> Result<(), Error> {
debug!("Done with crate");
- debug!("Adding Primitve impls");
+ debug!("Adding Primitive impls");
for primitive in Rc::clone(&self.cache).primitive_locations.values() {
self.get_impls(*primitive);
}
-Subproject commit e84a7928d93a31f284b497c214a2ece69b4d7719
+Subproject commit 82c3bb79e3a19a5164e33819ef81bfc2c984bc56
Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr)))
}
- fn alloc_base_addr(ecx: &MiriInterpCx<'mir, 'tcx>, alloc_id: AllocId) -> u64 {
+ fn alloc_base_addr(
+ ecx: &MiriInterpCx<'mir, 'tcx>,
+ alloc_id: AllocId,
+ ) -> InterpResult<'tcx, u64> {
let mut global_state = ecx.machine.intptrcast.borrow_mut();
let global_state = &mut *global_state;
- match global_state.base_addr.entry(alloc_id) {
+ Ok(match global_state.base_addr.entry(alloc_id) {
Entry::Occupied(entry) => *entry.get(),
Entry::Vacant(entry) => {
// There is nothing wrong with a raw pointer being cast to an integer only after
rng.gen_range(0..16)
};
// From next_base_addr + slack, round up to adjust for alignment.
- let base_addr = global_state.next_base_addr.checked_add(slack).unwrap();
+ let base_addr = global_state
+ .next_base_addr
+ .checked_add(slack)
+ .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
let base_addr = Self::align_addr(base_addr, align.bytes());
entry.insert(base_addr);
trace!(
// of at least 1 to avoid two allocations having the same base address.
// (The logic in `alloc_id_from_addr` assumes unique addresses, and different
// function/vtable pointers need to be distinguishable!)
- global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
+ global_state.next_base_addr = base_addr
+ .checked_add(max(size.bytes(), 1))
+ .ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
+ // Even if `Size` didn't overflow, we might still have filled up the address space.
+ if global_state.next_base_addr > ecx.machine_usize_max() {
+ throw_exhaust!(AddressSpaceFull);
+ }
// Given that `next_base_addr` increases in each allocation, pushing the
// corresponding tuple keeps `int_to_ptr_map` sorted
global_state.int_to_ptr_map.push((base_addr, alloc_id));
base_addr
}
- }
+ })
}
/// Convert a relative (tcx) pointer to an absolute address.
- pub fn rel_ptr_to_addr(ecx: &MiriInterpCx<'mir, 'tcx>, ptr: Pointer<AllocId>) -> u64 {
+ pub fn rel_ptr_to_addr(
+ ecx: &MiriInterpCx<'mir, 'tcx>,
+ ptr: Pointer<AllocId>,
+ ) -> InterpResult<'tcx, u64> {
let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
- let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+ let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id)?;
// Add offset with the right kind of pointer-overflowing arithmetic.
let dl = ecx.data_layout();
- dl.overflowing_offset(base_addr, offset.bytes()).0
+ Ok(dl.overflowing_offset(base_addr, offset.bytes()).0)
}
/// When a pointer is used for a memory access, this computes where in which allocation the
GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())?
};
- let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id);
+ // This cannot fail: since we already have a pointer with that provenance, rel_ptr_to_addr
+ // must have been called in the past.
+ let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id).unwrap();
// Wrapping "addr - base_addr"
let dl = ecx.data_layout();
fn adjust_alloc_base_pointer(
ecx: &MiriInterpCx<'mir, 'tcx>,
ptr: Pointer<AllocId>,
- ) -> Pointer<Provenance> {
+ ) -> InterpResult<'tcx, Pointer<Provenance>> {
if cfg!(debug_assertions) {
// The machine promises to never call us on thread-local or extern statics.
let alloc_id = ptr.provenance;
_ => {}
}
}
- let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr);
+ let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr)?;
let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine)
} else {
// Value does not matter, SB is disabled
BorTag::default()
};
- Pointer::new(
+ Ok(Pointer::new(
Provenance::Concrete { alloc_id: ptr.provenance, tag },
Size::from_bytes(absolute_addr),
- )
+ ))
}
#[inline(always)]
0 => {
// These are "mutable" allocations as we consider them to be owned by the callee.
let name_alloc =
- this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut);
+ this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
let filename_alloc =
- this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut);
+ this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?;
this.write_immediate(
name_alloc.to_ref(this),
let this = self.eval_context_mut();
// First arg: message.
- let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not);
+ let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?;
// Call the lang item.
let panic = this.tcx.lang_items().panic_fn().unwrap();
//@ignore-target-windows: No libc on Windows
-#![feature(cstr_from_bytes_until_nul)]
use std::ffi::{CStr, CString};
use std::thread;
-Subproject commit 5b2eee7eed72b4894909c5eecbf014ea0b5ad995
+Subproject commit 9981e4d1ea6ac0992ff21be5514d4230dc77548b
-Z llvm-plugins=val -- a list LLVM plugins to enable (space separated)
-Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
-Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`)
- -Z log-backtrace=val -- add a backtrace along with logging
-Z ls=val -- list the symbols defined by a library crate (default: no)
-Z macro-backtrace=val -- show macro backtraces (default: no)
-Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no)
impl Foo {
// @has async_fn/struct.Foo.html
- // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+ // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator<Item = &usize>'
pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
// taken from `tokio` as an example of a method that was particularly bad before
// @has - '//*[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
impl<const N: usize> Trait<N> for [u8; N] {}
// @has foo/struct.Foo.html '//pre[@class="rust item-decl"]' \
-// 'pub struct Foo<const N: usize>where u8: Trait<N>'
+// 'pub struct Foo<const N: usize> where u8: Trait<N>'
pub struct Foo<const N: usize> where u8: Trait<N>;
// @has foo/struct.Bar.html '//pre[@class="rust item-decl"]' 'pub struct Bar<T, const N: usize>(_)'
pub struct Bar<T, const N: usize>([T; N]);
<code>pub trait Write {
// Required methods
- fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
-<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
-<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>><br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+ fn <a href="#tymethod.poll_write" class="fn">poll_write</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
+<span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>;
// Provided method
- fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(<br />        self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,<br />        bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />    ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... }
-}</code>
+ fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>(
+ self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>,
+ bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]
+ ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... }
+}</code>
\ No newline at end of file
// @has foo/trait.LendingIterator.html
pub trait LendingIterator {
- // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a"
+ // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a"
type Item<'a> where Self: 'a;
// @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \
pub struct Infinite<T>(T);
// @has foo/trait.LendingIterator.html
-// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T"
+// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T"
impl<T> LendingIterator for Infinite<T> {
type Item<'a> where Self: 'a = &'a T;
// @has impl_trait/fn.func2.html
// @has - '//pre[@class="rust item-decl"]' "func2<T>("
// @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>,"
-// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>)"
+// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )"
// @!has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func2;
pub trait Bar {}
-// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T)where T: Bar;'
+// @has foo/struct.Foo.html '//pre' 'pub struct Foo<T>(pub T) where T: Bar;'
pub struct Foo<T>(pub T) where T: Bar;
pub use reexports::foo;
// @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()'
pub(crate) use reexports::foo_crate;
- // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()'
+ // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )'
pub(super) use::reexports::foo_super;
// @!has 'foo/outer/inner/fn.foo_self.html'
pub(self) use reexports::foo_self;
-<pre class="rust item-decl"><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>
\ No newline at end of file
+<pre class="rust item-decl"><code>pub struct Simd<T>(_)
+<span class="where">where
+ T: <a class="trait" href="trait.MyTrait.html" title="trait foo::MyTrait">MyTrait</a></span>;</code></pre>
\ No newline at end of file
<pre class="rust item-decl"><code>pub trait TraitWhere {
- type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a><br />       <span class="where">where Self: 'a</span>;
+ type <a href="#associatedtype.Item" class="associatedtype">Item</a><'a>
+ <span class="where">where Self: 'a</span>;
// Provided methods
- fn <a href="#method.func" class="fn">func</a>(self)<br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" /> fn <a href="#method.lines" class="fn">lines</a>(self) -> <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a><Self><br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
-<span class="item-spacer" /> fn <a href="#method.merge" class="fn">merge</a><T>(self, a: T)<br />       <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,<br />             T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+ fn <a href="#method.func" class="fn">func</a>(self)
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" /> fn <a href="#method.lines" class="fn">lines</a>(self) -> <a class="struct" href="{{channel}}/std/io/struct.Lines.html" title="struct std::io::Lines">Lines</a><Self>
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
+<span class="item-spacer" /> fn <a href="#method.merge" class="fn">merge</a><T>(self, a: T)
+ <span class="where">where Self: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a>,
+ T: <a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a></span> { ... }
}</code></pre>
\ No newline at end of file
pub trait MyTrait { fn dummy(&self) { } }
-// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_)where A: MyTrait"
+// @has foo/struct.Alpha.html '//pre' "pub struct Alpha<A>(_) where A: MyTrait"
pub struct Alpha<A>(A) where A: MyTrait;
// @has foo/trait.Bravo.html '//pre' "pub trait Bravo<B>where B: MyTrait"
pub trait Bravo<B> where B: MyTrait { fn get(&self, B: B); }
-<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub enum Cow<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>),
Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
}</code></pre>
\ No newline at end of file
-<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub struct Struct<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&'a B</a>,
pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
}</code></pre>
\ No newline at end of file
-<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where<br />    T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
+<pre class="rust item-decl"><code>pub trait ToOwned<T><span class="where fmt-newline">where
+ T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,</span>{
type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
// Required methods
-<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where<br />    B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
+<pre class="rust item-decl"><code>pub union Union<'a, B><span class="where fmt-newline">where
+ B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a><dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>> + ?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a,</span>{
/* private fields */
}</code></pre>
\ No newline at end of file
// run-pass
//
-// This test makes sure that log-backtrace option doesn't give a compilation error.
+// This test makes sure that log-backtrace option at least parses correctly
//
// dont-check-compiler-stdout
// dont-check-compiler-stderr
// rustc-env:RUSTC_LOG=info
-// compile-flags: -Zlog-backtrace=rustc_metadata::creader
+// rustc-env:RUSTC_LOG_BACKTRACE=rustc_metadata::creader
fn main() {}
// compile-flags: -Ztreat-err-as-bug=1
// failure-status: 101
// rustc-env:RUST_BACKTRACE=1
-// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> ""
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
+// normalize-stderr-test "\nerror: .*unexpectedly panicked.*\n\n" -> ""
// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
error[E0080]: evaluation of constant value failed
- --> $DIR/const-eval-query-stack.rs:17:16
+ --> $DIR/const-eval-query-stack.rs:16:16
|
LL | const X: i32 = 1 / 0;
| ^^^^^ attempt to divide `1_i32` by zero
//~^^ this was previously accepted
}
+// Again, currently allowed, but will be phased out.
+#[derive(Debug)]
+#[repr(packed)]
+struct WithStr {
+ width: u8,
+ data: str,
+ //~^ WARNING string slice in a packed struct that derives a built-in trait
+ //~^^ this was previously accepted
+}
+
fn main() {}
= note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
= note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+warning: string slice in a packed struct that derives a built-in trait
+ --> $DIR/deriving-with-repr-packed.rs:41:5
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+...
+LL | data: str,
+ | ^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+ = help: consider implementing the trait by hand, or remove the `packed` attribute
+ = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
error[E0507]: cannot move out of `self` which is behind a shared reference
--> $DIR/deriving-with-repr-packed.rs:22:10
|
|
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error; 2 warnings emitted
For more information about this error, try `rustc --explain E0507`.
Future incompatibility report: Future breakage diagnostic:
= note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
= note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+Future breakage diagnostic:
+warning: string slice in a packed struct that derives a built-in trait
+ --> $DIR/deriving-with-repr-packed.rs:41:5
+ |
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+...
+LL | data: str,
+ | ^^^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+ = help: consider implementing the trait by hand, or remove the `packed` attribute
+ = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+ = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
-error[E0277]: `AlignedUsize` needs to be a pointer-sized type
+error[E0277]: `AlignedUsize` needs to have the same alignment and size as a pointer
--> $DIR/align.rs:15:13
|
LL | let x = AlignedUsize(12) as dyn* Debug;
- | ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-sized type
+ | ^^^^^^^^^^^^^^^^ `AlignedUsize` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `AlignedUsize`
+ = help: the trait `PointerLike` is not implemented for `AlignedUsize`
error: aborting due to previous error; 1 warning emitted
fn main() {
let x = AlignedUsize(12) as dyn* Debug;
- //[over_aligned]~^ ERROR `AlignedUsize` needs to be a pointer-sized type
+ //[over_aligned]~^ ERROR `AlignedUsize` needs to have the same alignment and size as a pointer
}
fn polymorphic<T: Debug + ?Sized>(t: &T) {
dyn_debug(t);
- //~^ ERROR `&T` needs to be a pointer-sized type
+ //~^ ERROR `&T` needs to have the same alignment and size as a pointer
}
fn main() {}
-error[E0277]: `&T` needs to be a pointer-sized type
+error[E0277]: `&T` needs to have the same alignment and size as a pointer
--> $DIR/check-size-at-cast-polymorphic-bad.rs:11:15
|
LL | dyn_debug(t);
- | ^ `&T` needs to be a pointer-sized type
+ | ^ `&T` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `&T`
+ = help: the trait `PointerLike` is not implemented for `&T`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
-LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerSized {
- | ++++++++++++++++++++++
+LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
+ | +++++++++++++++++++++
error: aborting due to previous error
fn main() {
let i = [1, 2, 3, 4] as dyn* Debug;
- //~^ ERROR `[i32; 4]` needs to be a pointer-sized type
+ //~^ ERROR `[i32; 4]` needs to have the same alignment and size as a pointer
dbg!(i);
}
-error[E0277]: `[i32; 4]` needs to be a pointer-sized type
+error[E0277]: `[i32; 4]` needs to have the same alignment and size as a pointer
--> $DIR/check-size-at-cast.rs:7:13
|
LL | let i = [1, 2, 3, 4] as dyn* Debug;
- | ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-sized type
+ | ^^^^^^^^^^^^ `[i32; 4]` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `[i32; 4]`
+ = help: the trait `PointerLike` is not implemented for `[i32; 4]`
error: aborting due to previous error
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
-error[E0277]: `dyn* Foo` needs to be a pointer-sized type
+error[E0277]: `dyn* Foo` needs to have the same alignment and size as a pointer
--> $DIR/upcast.rs:30:23
|
LL | let w: dyn* Bar = w;
- | ^ `dyn* Foo` needs to be a pointer-sized type
+ | ^ `dyn* Foo` needs to be a pointer-like type
|
- = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+ = help: the trait `PointerLike` is not implemented for `dyn* Foo`
error: aborting due to previous error; 1 warning emitted
// known-bug: #106191
// unset-rustc-env:RUST_BACKTRACE
// had to be reverted
-// error-pattern:internal compiler error
+// error-pattern:unexpectedly panicked
// failure-status:101
// dont-check-compiler-stderr
stack backtrace:
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [layout_of] computing layout of `Foo`
stringify_item!(
impl ~const Struct {}
),
- "impl Struct {}", // FIXME
+ "impl ~const Struct {}",
);
// ItemKind::MacCall
assert_eq!(stringify_ty!(dyn Send + 'a), "dyn Send + 'a");
assert_eq!(stringify_ty!(dyn 'a + Send), "dyn 'a + Send");
assert_eq!(stringify_ty!(dyn ?Sized), "dyn ?Sized");
- assert_eq!(stringify_ty!(dyn ~const Clone), "dyn Clone"); // FIXME
+ assert_eq!(stringify_ty!(dyn ~const Clone), "dyn ~const Clone");
assert_eq!(stringify_ty!(dyn for<'a> Send), "dyn for<'a> Send");
// TyKind::ImplTrait
assert_eq!(stringify_ty!(impl Send + 'a), "impl Send + 'a");
assert_eq!(stringify_ty!(impl 'a + Send), "impl 'a + Send");
assert_eq!(stringify_ty!(impl ?Sized), "impl ?Sized");
- assert_eq!(stringify_ty!(impl ~const Clone), "impl Clone"); // FIXME
+ assert_eq!(stringify_ty!(impl ~const Clone), "impl ~const Clone");
assert_eq!(stringify_ty!(impl for<'a> Send), "impl for<'a> Send");
// TyKind::Paren
--- /dev/null
+// build-pass
+
+#![crate_type = "lib"]
+
+pub trait StreamOnce {
+ type Error;
+}
+
+pub trait ResetStream: StreamOnce {
+ fn reset(&mut self) -> Result<(), Self::Error>;
+}
+
+impl<'a> ResetStream for &'a str
+ where Self: StreamOnce
+{
+ #[inline]
+ fn reset(&mut self) -> Result<(), Self::Error> {
+ Ok(())
+ }
+}
--- /dev/null
+// build-pass
+// compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+
+pub trait Archive {
+ type Archived;
+ type Resolver;
+
+ fn resolve(resolver: Self::Resolver, out: *mut Self::Archived);
+}
+
+pub type Archived<T> = <T as Archive>::Archived;
+pub type Resolver<T> = <T as Archive>::Resolver;
+
+pub struct Record<'a> {
+ _payload: &'a [u8],
+}
+
+pub struct ArchivedRecord<'a>
+where
+ &'a [u8]: Archive,
+{
+ _payload: Archived<&'a [u8]>,
+}
+
+pub struct RecordResolver<'a>
+where
+ &'a [u8]: Archive,
+{
+ _payload: Resolver<&'a [u8]>,
+}
+
+impl<'a> Archive for Record<'a>
+where
+ &'a [u8]: Archive,
+{
+ type Archived = ArchivedRecord<'a>;
+ type Resolver = RecordResolver<'a>;
+
+ fn resolve(_resolver: Self::Resolver, _out: *mut Self::Archived) {}
+}
stack backtrace:
-error: internal compiler error: unexpected panic
-
-
+error: the compiler unexpectedly panicked. this is a bug.
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
-error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>: Iterator`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
+ = note: required for `&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:12:24: 12:27]>` to implement `Iterator`
+ = note: 65 redundant requirements hidden
= note: required for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<..., ...>, ...>, ...>, ...>, ...>, ...>, ...>` to implement `Iterator`
= note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-83150/issue-83150.long-type-hash.txt'
--- /dev/null
+// check-pass
+
+#![feature(derive_const)]
+#![feature(const_trait_impl)]
+
+#[derive_const(PartialEq)]
+pub struct Reverse<T>(T);
+
+const fn foo(a: Reverse<i32>, b: Reverse<i32>) -> bool {
+ a == b
+}
+
+fn main() {}
--- /dev/null
+// compile-flags: -Ztrait-solver=next
+
+#![feature(pointer_like_trait)]
+
+use std::marker::PointerLike;
+
+fn require_(_: impl PointerLike) {}
+
+fn main() {
+ require_(1usize);
+ require_(1u16);
+ //~^ ERROR `u16` needs to have the same alignment and size as a pointer
+ require_(&1i16);
+}
--- /dev/null
+error[E0277]: `u16` needs to have the same alignment and size as a pointer
+ --> $DIR/pointer-like.rs:11:14
+ |
+LL | require_(1u16);
+ | -------- ^^^^ the trait `PointerLike` is not implemented for `u16`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: the trait bound `u16: PointerLike` is not satisfied
+note: required by a bound in `require_`
+ --> $DIR/pointer-like.rs:7:21
+ |
+LL | fn require_(_: impl PointerLike) {}
+ | ^^^^^^^^^^^ required by this bound in `require_`
+help: consider borrowing here
+ |
+LL | require_(&1u16);
+ | +
+LL | require_(&mut 1u16);
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(pointer_sized_trait)]
-
-use std::marker::PointerSized;
-
-fn require_pointer_sized(_: impl PointerSized) {}
-
-fn main() {
- require_pointer_sized(1usize);
- require_pointer_sized(1u16);
- //~^ ERROR `u16` needs to be a pointer-sized type
- require_pointer_sized(&1i16);
-}
+++ /dev/null
-error[E0277]: `u16` needs to be a pointer-sized type
- --> $DIR/pointer-sized.rs:9:27
- |
-LL | require_pointer_sized(1u16);
- | --------------------- ^^^^ the trait `PointerSized` is not implemented for `u16`
- | |
- | required by a bound introduced by this call
- |
- = note: the trait bound `u16: PointerSized` is not satisfied
-note: required by a bound in `require_pointer_sized`
- --> $DIR/pointer-sized.rs:5:34
- |
-LL | fn require_pointer_sized(_: impl PointerSized) {}
- | ^^^^^^^^^^^^ required by this bound in `require_pointer_sized`
-help: consider borrowing here
- |
-LL | require_pointer_sized(&1u16);
- | +
-LL | require_pointer_sized(&mut 1u16);
- | ++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// known-bug: unknown
+// compile-flags: -Ztrait-solver=next
+// failure-status: 101
+// normalize-stderr-test "note: .*\n\n" -> ""
+// normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+// rustc-env:RUST_BACKTRACE=0
+
+// This tests checks that we update results in the provisional cache when
+// we pop a goal from the stack.
+#![feature(auto_traits)]
+auto trait Coinductive {}
+struct Foo<T>(T);
+struct Bar<T>(T);
+
+impl<T> Coinductive for Foo<T>
+where
+ Bar<T>: Coinductive
+{}
+
+impl<T> Coinductive for Bar<T>
+where
+ Foo<T>: Coinductive,
+ Bar<T>: ConstrainInfer,
+{}
+
+trait ConstrainInfer {}
+impl ConstrainInfer for Bar<u8> {}
+impl ConstrainInfer for Foo<u16> {}
+
+fn impls<T: Coinductive>() -> T { todo!() }
+
+fn constrain<T: ConstrainInfer>(_: T) {}
+
+fn main() {
+ // This should constrain `_` to `u8`.
+ impls::<Foo<_>>();
+}
--- /dev/null
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [check_well_formed] checking that `<impl at $DIR/provisional-result-done.rs:20:1: 20:31>` is well-formed
+#1 [check_mod_type_wf] checking that types are well-formed in top-level module
+end of query stack
LL | fn main() {}
| ^^^^^^^^^
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [trigger_delay_span_bug] triggering a delay span bug
LL | pub static C: u32 = 0 - 1;
| ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow
-error: internal compiler error: unexpected panic
+error: the compiler unexpectedly panicked. this is a bug.
query stack during panic:
#0 [eval_to_allocation_raw] const-evaluating + checking `C`
--- /dev/null
+// edition: 2021
+
+use std::collections::HashMap;
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait Trait {
+ fn do_something<'async_trait>(byte: u8)
+ ->
+ Pin<Box<dyn Future<Output = ()> +
+ Send + 'async_trait>>;
+}
+
+pub struct Struct;
+
+impl Trait for Struct {
+ fn do_something<'async_trait>(byte: u8)
+ ->
+ Pin<Box<dyn Future<Output = ()> +
+ Send + 'async_trait>> {
+ Box::pin(
+
+ async move { let byte = byte; let _: () = {}; })
+ }
+}
+
+pub struct Map {
+ map: HashMap<u16, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
+}
+
+impl Map {
+ pub fn new() -> Self {
+ let mut map = HashMap::new();
+ map.insert(1, Struct::do_something);
+ Self { map }
+ //~^ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-107775.rs:35:16
+ |
+LL | map.insert(1, Struct::do_something);
+ | - -------------------- this is of type `fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+ | |
+ | this is of type `{integer}`, which causes `map` to be inferred as `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+LL | Self { map }
+ | ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>`
+ |
+ = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
+ found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// compile-flags: -Zunpretty=normal
+// check-pass
+
+fn foo() where T: ~const Bar {}
--- /dev/null
+// compile-flags: -Zunpretty=normal
+// check-pass
+
+fn foo() where T: ~const Bar {}