Merge from rustc
This commit is contained in:
commit
2fccb4b358
739 changed files with 5703 additions and 2574 deletions
2
.mailmap
2
.mailmap
|
@ -81,6 +81,7 @@ boolean_coercion <booleancoercion@gmail.com>
|
|||
Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com>
|
||||
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
|
||||
Boxy <rust@boxyuwu.dev> <supbscripter@gmail.com>
|
||||
Braden Nelson <moonheart08@users.noreply.github.com>
|
||||
Brandon Sanderson <singingboyo@gmail.com> Brandon Sanderson <singingboyo@hotmail.com>
|
||||
Brett Cannon <brett@python.org> Brett Cannon <brettcannon@users.noreply.github.com>
|
||||
|
@ -146,6 +147,7 @@ David Klein <david.klein@baesystemsdetica.com>
|
|||
David Manescu <david.manescu@gmail.com> <dman2626@uni.sydney.edu.au>
|
||||
David Ross <daboross@daboross.net>
|
||||
David Wood <david@davidtw.co> <david.wood@huawei.com>
|
||||
David Wood <david@davidtw.co> <david.wood2@arm.com>
|
||||
Deadbeef <ent3rm4n@gmail.com>
|
||||
Deadbeef <ent3rm4n@gmail.com> <fee1-dead-beef@protonmail.com>
|
||||
dependabot[bot] <dependabot[bot]@users.noreply.github.com> <27856297+dependabot-preview[bot]@users.noreply.github.com>
|
||||
|
|
38
Cargo.lock
38
Cargo.lock
|
@ -199,7 +199,7 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4"
|
||||
dependencies = [
|
||||
"object 0.36.3",
|
||||
"object 0.36.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2453,9 +2453,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.3"
|
||||
version = "0.36.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
|
||||
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
|
@ -2463,7 +2463,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"memchr",
|
||||
"ruzstd 0.7.0",
|
||||
"wasmparser 0.215.0",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3129,11 +3129,11 @@ dependencies = [
|
|||
"build_helper",
|
||||
"gimli 0.31.0",
|
||||
"libc",
|
||||
"object 0.36.3",
|
||||
"object 0.36.4",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"wasmparser 0.216.0",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3408,7 +3408,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object 0.36.3",
|
||||
"object 0.36.4",
|
||||
"rustc-demangle",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
|
@ -3447,7 +3447,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"object 0.36.3",
|
||||
"object 0.36.4",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_arena",
|
||||
|
@ -3569,6 +3569,7 @@ dependencies = [
|
|||
"rustc_hir_pretty",
|
||||
"rustc_hir_typeck",
|
||||
"rustc_incremental",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_interface",
|
||||
"rustc_lint",
|
||||
|
@ -4431,7 +4432,7 @@ name = "rustc_target"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"object 0.36.3",
|
||||
"object 0.36.4",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_feature",
|
||||
|
@ -5849,7 +5850,7 @@ dependencies = [
|
|||
"lexopt",
|
||||
"tempfile",
|
||||
"wasi-preview1-component-adapter-provider",
|
||||
"wasmparser 0.216.0",
|
||||
"wasmparser",
|
||||
"wat",
|
||||
"wit-component",
|
||||
"wit-parser",
|
||||
|
@ -5869,7 +5870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
"wasmparser 0.216.0",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5885,16 +5886,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder",
|
||||
"wasmparser 0.216.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.215.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fbde0881f24199b81cf49b6ff8f9c145ac8eb1b7fc439adb5c099734f7d90e"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6228,7 +6220,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"wasm-encoder",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.216.0",
|
||||
"wasmparser",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
|
@ -6247,7 +6239,7 @@ dependencies = [
|
|||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.216.0",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -112,6 +112,14 @@ tools.
|
|||
|
||||
- [Add a Rust-for Linux `auto` CI job to check kernel builds.](https://github.com/rust-lang/rust/pull/125209/)
|
||||
|
||||
Version 1.80.1 (2024-08-08)
|
||||
===========================
|
||||
|
||||
<a id="1.80.1"></a>
|
||||
|
||||
- [Fix miscompilation in the jump threading MIR optimization when comparing floats](https://github.com/rust-lang/rust/pull/128271)
|
||||
- [Revert changes to the `dead_code` lint from 1.80.0](https://github.com/rust-lang/rust/pull/128618)
|
||||
|
||||
Version 1.80.0 (2024-07-25)
|
||||
==========================
|
||||
|
||||
|
|
|
@ -30,5 +30,6 @@ features = ['unprefixed_malloc_on_supported_platforms']
|
|||
jemalloc = ['dep:jemalloc-sys']
|
||||
llvm = ['rustc_driver_impl/llvm']
|
||||
max_level_info = ['rustc_driver_impl/max_level_info']
|
||||
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
|
||||
rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -968,8 +968,8 @@ fn univariant<
|
|||
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
|
||||
let mut max_repr_align = repr.align;
|
||||
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
||||
let optimize = !repr.inhibit_struct_field_reordering();
|
||||
if optimize && fields.len() > 1 {
|
||||
let optimize_field_order = !repr.inhibit_struct_field_reordering();
|
||||
if optimize_field_order && fields.len() > 1 {
|
||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||
let fields_excluding_tail = &fields.raw[..end];
|
||||
|
@ -1176,7 +1176,7 @@ fn univariant<
|
|||
// If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
|
||||
// Field 5 would be the first element, so memory_index is i:
|
||||
// Note: if we didn't optimize, it's already right.
|
||||
let memory_index = if optimize {
|
||||
let memory_index = if optimize_field_order {
|
||||
inverse_memory_index.invert_bijective_mapping()
|
||||
} else {
|
||||
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
|
||||
|
@ -1189,6 +1189,9 @@ fn univariant<
|
|||
}
|
||||
let mut layout_of_single_non_zst_field = None;
|
||||
let mut abi = Abi::Aggregate { sized };
|
||||
|
||||
let optimize_abi = !repr.inhibit_newtype_abi_optimization();
|
||||
|
||||
// Try to make this a Scalar/ScalarPair.
|
||||
if sized && size.bytes() > 0 {
|
||||
// We skip *all* ZST here and later check if we are good in terms of alignment.
|
||||
|
@ -1205,7 +1208,7 @@ fn univariant<
|
|||
match field.abi {
|
||||
// For plain scalars, or vectors of them, we can't unpack
|
||||
// newtypes for `#[repr(C)]`, as that affects C ABIs.
|
||||
Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
|
||||
Abi::Scalar(_) | Abi::Vector { .. } if optimize_abi => {
|
||||
abi = field.abi;
|
||||
}
|
||||
// But scalar pairs are Rust-specific and get
|
||||
|
|
|
@ -43,14 +43,17 @@ bitflags! {
|
|||
const IS_SIMD = 1 << 1;
|
||||
const IS_TRANSPARENT = 1 << 2;
|
||||
// Internal only for now. If true, don't reorder fields.
|
||||
// On its own it does not prevent ABI optimizations.
|
||||
const IS_LINEAR = 1 << 3;
|
||||
// If true, the type's layout can be randomized using
|
||||
// the seed stored in `ReprOptions.field_shuffle_seed`
|
||||
// If true, the type's crate has opted into layout randomization.
|
||||
// Other flags can still inhibit reordering and thus randomization.
|
||||
// The seed stored in `ReprOptions.field_shuffle_seed`.
|
||||
const RANDOMIZE_LAYOUT = 1 << 4;
|
||||
// Any of these flags being set prevent field reordering optimisation.
|
||||
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits()
|
||||
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
|
||||
| ReprFlags::IS_SIMD.bits()
|
||||
| ReprFlags::IS_LINEAR.bits();
|
||||
const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,10 +142,14 @@ impl ReprOptions {
|
|||
self.c() || self.int.is_some()
|
||||
}
|
||||
|
||||
pub fn inhibit_newtype_abi_optimization(&self) -> bool {
|
||||
self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE)
|
||||
}
|
||||
|
||||
/// Returns `true` if this `#[repr()]` guarantees a fixed field order,
|
||||
/// e.g. `repr(C)` or `repr(<int>)`.
|
||||
pub fn inhibit_struct_field_reordering(&self) -> bool {
|
||||
self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some()
|
||||
self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
|
||||
|
|
|
@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn has_self(&self, def_id: DefId, span: Span) -> bool {
|
||||
if let Some(local_sig_id) = def_id.as_local() {
|
||||
// The value may be missing due to recursive delegation.
|
||||
// Error will be emmited later during HIR ty lowering.
|
||||
// Error will be emitted later during HIR ty lowering.
|
||||
self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self)
|
||||
} else {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
|
@ -139,7 +139,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
// Map may be filled incorrectly due to recursive delegation.
|
||||
// Error will be emmited later during HIR ty lowering.
|
||||
// Error will be emitted later during HIR ty lowering.
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||
None => (0, false),
|
||||
|
|
|
@ -1179,7 +1179,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
for field in &variant.fields {
|
||||
// In practice unless there are more than one field with the same type, we'll be
|
||||
// suggesting a single field at a type, because we don't aggregate multiple borrow
|
||||
// checker errors involving the functional record update sytnax into a single one.
|
||||
// checker errors involving the functional record update syntax into a single one.
|
||||
let field_ty = field.ty(self.infcx.tcx, args);
|
||||
let ident = field.ident(self.infcx.tcx);
|
||||
if field_ty == ty && fields.iter().all(|field| field.ident.name != ident.name) {
|
||||
|
|
|
@ -218,7 +218,7 @@ impl<'a, 'me, 'typeck, 'flow, 'tcx> LivenessResults<'a, 'me, 'typeck, 'flow, 'tc
|
|||
// This collect is more necessary than immediately apparent
|
||||
// because these facts go into `add_drop_live_facts_for()`,
|
||||
// which also writes to `all_facts`, and so this is genuinely
|
||||
// a simulatneous overlapping mutable borrow.
|
||||
// a simultaneous overlapping mutable borrow.
|
||||
// FIXME for future hackers: investigate whether this is
|
||||
// actually necessary; these facts come from Polonius
|
||||
// and probably maybe plausibly does not need to go back in.
|
||||
|
|
|
@ -390,7 +390,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
let val_llty = self.val_ty(v);
|
||||
|
||||
let g = self.get_static_inner(def_id, val_llty);
|
||||
let llty = self.val_ty(g);
|
||||
let llty = llvm::LLVMGlobalGetValueType(g);
|
||||
|
||||
let g = if val_llty == llty {
|
||||
g
|
||||
|
|
|
@ -422,7 +422,7 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
|
|||
(instance.def_id(), body)
|
||||
});
|
||||
|
||||
// Functions whose coverage statments were found inlined into other functions.
|
||||
// Functions whose coverage statements were found inlined into other functions.
|
||||
let mut used_via_inlining = FxHashSet::default();
|
||||
// Functions that were instrumented, but had all of their coverage statements
|
||||
// removed by later MIR transforms (e.g. UnreachablePropagation).
|
||||
|
|
|
@ -187,9 +187,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
Some(instance),
|
||||
)
|
||||
}
|
||||
sym::likely => {
|
||||
self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
|
||||
}
|
||||
sym::likely => self.expect(args[0].immediate(), true),
|
||||
sym::is_val_statically_known => {
|
||||
let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
|
||||
let kind = self.type_kind(intrinsic_type);
|
||||
|
@ -210,8 +208,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
self.const_bool(false)
|
||||
}
|
||||
}
|
||||
sym::unlikely => self
|
||||
.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
|
||||
sym::unlikely => self.expect(args[0].immediate(), false),
|
||||
sym::select_unpredictable => {
|
||||
let cond = args[0].immediate();
|
||||
assert_eq!(args[1].layout, args[2].layout);
|
||||
|
@ -604,11 +601,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn assume(&mut self, val: Self::Value) {
|
||||
self.call_intrinsic("llvm.assume", &[val]);
|
||||
if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
|
||||
self.call_intrinsic("llvm.assume", &[val]);
|
||||
}
|
||||
}
|
||||
|
||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
|
||||
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
|
||||
if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
|
||||
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
|
||||
} else {
|
||||
cond
|
||||
}
|
||||
}
|
||||
|
||||
fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
|
||||
|
|
|
@ -974,6 +974,7 @@ unsafe extern "C" {
|
|||
pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
|
||||
pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
|
||||
pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
|
||||
pub fn LLVMGlobalGetValueType(Global: &Value) -> &Type;
|
||||
|
||||
// Operations on global variables
|
||||
pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
|
||||
|
|
|
@ -701,7 +701,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||
match ty.kind() {
|
||||
ty::Int(ity) => {
|
||||
// FIXME: directly extract the bits from a valtree instead of evaluating an
|
||||
// alreay evaluated `Const` in order to get the bits.
|
||||
// already evaluated `Const` in order to get the bits.
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
|
|
|
@ -382,7 +382,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
scalar: abi::Scalar,
|
||||
backend_ty: Bx::Type,
|
||||
) {
|
||||
if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less)
|
||||
if matches!(self.cx.sess().opts.optimize, OptLevel::No)
|
||||
// For now, the critical niches are all over `Int`eger values.
|
||||
// Should floating-point values or pointers ever get more complex
|
||||
// niches, then this code will probably want to handle them too.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_middle::mir::{self, NonDivergingIntrinsic};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_session::config::OptLevel;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::{FunctionCx, LocalRef};
|
||||
|
@ -68,10 +67,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.codegen_coverage(bx, kind, statement.source_info.scope);
|
||||
}
|
||||
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => {
|
||||
if !matches!(bx.tcx().sess.opts.optimize, OptLevel::No | OptLevel::Less) {
|
||||
let op_val = self.codegen_operand(bx, op);
|
||||
bx.assume(op_val.immediate());
|
||||
}
|
||||
let op_val = self.codegen_operand(bx, op);
|
||||
bx.assume(op_val.immediate());
|
||||
}
|
||||
mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
|
||||
mir::CopyNonOverlapping { ref count, ref src, ref dst },
|
||||
|
|
|
@ -46,7 +46,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary
|
||||
pub fn needs_drop(
|
||||
fn needs_drop(
|
||||
&mut self,
|
||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||
local: Local,
|
||||
|
@ -76,7 +76,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary
|
||||
pub fn needs_non_const_drop(
|
||||
pub(crate) fn needs_non_const_drop(
|
||||
&mut self,
|
||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||
local: Local,
|
||||
|
@ -106,7 +106,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
|
||||
///
|
||||
/// Only updates the cursor if absolutely necessary.
|
||||
pub fn has_mut_interior(
|
||||
fn has_mut_interior(
|
||||
&mut self,
|
||||
ccx: &'mir ConstCx<'mir, 'tcx>,
|
||||
local: Local,
|
||||
|
|
|
@ -57,7 +57,7 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug {
|
|||
|
||||
/// A function call where the callee is a pointer.
|
||||
#[derive(Debug)]
|
||||
pub struct FnCallIndirect;
|
||||
pub(crate) struct FnCallIndirect;
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
|
||||
|
@ -66,7 +66,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
|
|||
|
||||
/// A function call where the callee is not marked as `const`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FnCallNonConst<'tcx> {
|
||||
pub(crate) struct FnCallNonConst<'tcx> {
|
||||
pub caller: LocalDefId,
|
||||
pub callee: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
|
@ -299,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
///
|
||||
/// Contains the name of the feature that would allow the use of this function.
|
||||
#[derive(Debug)]
|
||||
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
||||
pub(crate) struct FnCallUnstable(pub DefId, pub Option<Symbol>);
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
|
@ -324,7 +324,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Coroutine(pub hir::CoroutineKind);
|
||||
pub(crate) struct Coroutine(pub hir::CoroutineKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::CoroutineKind::Desugared(
|
||||
|
@ -356,7 +356,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HeapAllocation;
|
||||
pub(crate) struct HeapAllocation;
|
||||
impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::UnallowedHeapAllocations {
|
||||
|
@ -368,7 +368,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InlineAsm;
|
||||
pub(crate) struct InlineAsm;
|
||||
impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
|
||||
|
@ -376,7 +376,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LiveDrop<'tcx> {
|
||||
pub(crate) struct LiveDrop<'tcx> {
|
||||
pub dropped_at: Option<Span>,
|
||||
pub dropped_ty: Ty<'tcx>,
|
||||
}
|
||||
|
@ -394,7 +394,7 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
|
|||
#[derive(Debug)]
|
||||
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
|
||||
/// the final value of the constant.
|
||||
pub struct TransientCellBorrow;
|
||||
pub(crate) struct TransientCellBorrow;
|
||||
impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_refs_to_cell)
|
||||
|
@ -410,7 +410,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
|||
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
|
||||
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
|
||||
/// it in the future for static items.
|
||||
pub struct CellBorrow;
|
||||
pub(crate) struct CellBorrow;
|
||||
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
|
||||
fn importance(&self) -> DiagImportance {
|
||||
// Most likely the code will try to do mutation with these borrows, which
|
||||
|
@ -431,7 +431,7 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow {
|
|||
/// This op is for `&mut` borrows in the trailing expression of a constant
|
||||
/// which uses the "enclosing scopes rule" to leak its locals into anonymous
|
||||
/// static or const items.
|
||||
pub struct MutBorrow(pub hir::BorrowKind);
|
||||
pub(crate) struct MutBorrow(pub hir::BorrowKind);
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for MutBorrow {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
|
@ -461,7 +461,7 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TransientMutBorrow(pub hir::BorrowKind);
|
||||
pub(crate) struct TransientMutBorrow(pub hir::BorrowKind);
|
||||
|
||||
impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
|
@ -484,7 +484,7 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutDeref;
|
||||
pub(crate) struct MutDeref;
|
||||
impl<'tcx> NonConstOp<'tcx> for MutDeref {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
|
@ -505,7 +505,7 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref {
|
|||
|
||||
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
|
||||
#[derive(Debug)]
|
||||
pub struct PanicNonStr;
|
||||
pub(crate) struct PanicNonStr;
|
||||
impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::PanicNonStrErr { span })
|
||||
|
@ -516,7 +516,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
|
|||
/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
|
||||
/// allocation base addresses that are not known at compile-time.
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrComparison;
|
||||
pub(crate) struct RawPtrComparison;
|
||||
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
// FIXME(const_trait_impl): revert to span_bug?
|
||||
|
@ -525,7 +525,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawMutPtrDeref;
|
||||
pub(crate) struct RawMutPtrDeref;
|
||||
impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
|
@ -546,7 +546,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
|
|||
/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
|
||||
/// allocation base addresses that are not known at compile-time.
|
||||
#[derive(Debug)]
|
||||
pub struct RawPtrToIntCast;
|
||||
pub(crate) struct RawPtrToIntCast;
|
||||
impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::RawPtrToIntErr { span })
|
||||
|
@ -555,7 +555,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
|
|||
|
||||
/// An access to a (non-thread-local) `static`.
|
||||
#[derive(Debug)]
|
||||
pub struct StaticAccess;
|
||||
pub(crate) struct StaticAccess;
|
||||
impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
||||
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||
|
@ -582,7 +582,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
|
|||
|
||||
/// An access to a thread-local `static`.
|
||||
#[derive(Debug)]
|
||||
pub struct ThreadLocalAccess;
|
||||
pub(crate) struct ThreadLocalAccess;
|
||||
impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
|
||||
ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
|
||||
|
@ -590,11 +590,11 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
|
|||
}
|
||||
|
||||
/// Types that cannot appear in the signature or locals of a `const fn`.
|
||||
pub mod mut_ref {
|
||||
pub(crate) mod mut_ref {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutRef(pub mir::LocalKind);
|
||||
pub(crate) struct MutRef(pub mir::LocalKind);
|
||||
impl<'tcx> NonConstOp<'tcx> for MutRef {
|
||||
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_mut_refs)
|
||||
|
|
|
@ -20,7 +20,7 @@ use super::{
|
|||
};
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
/// An argment passed to a function.
|
||||
/// An argument passed to a function.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
|
||||
/// Pass a copy of the given operand.
|
||||
|
@ -123,7 +123,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
|
||||
};
|
||||
let inner = self.unfold_transparent(inner, /* may_unfold */ |def| {
|
||||
// Stop at NPO tpyes so that we don't miss that attribute in the check below!
|
||||
// Stop at NPO types so that we don't miss that attribute in the check below!
|
||||
def.is_struct() && !is_npo(def)
|
||||
});
|
||||
Ok(match inner.ty.kind() {
|
||||
|
|
|
@ -574,7 +574,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// be computed as the type references non-existing names.
|
||||
// See <https://github.com/rust-lang/rust/issues/124348>.
|
||||
} else {
|
||||
// Looks like the const is not captued by `required_consts`, that's bad.
|
||||
// Looks like the const is not captured by `required_consts`, that's bad.
|
||||
span_bug!(span, "interpret const eval failure of {val:?} which is not in required_consts");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -827,7 +827,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
|
||||
let (size, align) = if nested {
|
||||
// Nested anonymous statics are untyped, so let's get their
|
||||
// size and alignment from the allocaiton itself. This always
|
||||
// size and alignment from the allocation itself. This always
|
||||
// succeeds, as the query is fed at DefId creation time, so no
|
||||
// evaluation actually occurs.
|
||||
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
|
||||
|
|
|
@ -61,13 +61,13 @@ pub(super) struct MemPlace<Prov: Provenance = CtfeProvenance> {
|
|||
|
||||
impl<Prov: Provenance> MemPlace<Prov> {
|
||||
/// Adjust the provenance of the main pointer (metadata is unaffected).
|
||||
pub fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self {
|
||||
fn map_provenance(self, f: impl FnOnce(Prov) -> Prov) -> Self {
|
||||
MemPlace { ptr: self.ptr.map_provenance(|p| p.map(f)), ..self }
|
||||
}
|
||||
|
||||
/// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space.
|
||||
#[inline]
|
||||
pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> {
|
||||
fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> {
|
||||
Immediate::new_pointer_with_meta(self.ptr, self.meta, cx)
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ pub(super) enum Place<Prov: Provenance = CtfeProvenance> {
|
|||
/// `Local` places always refer to the current stack frame, so they are unstable under
|
||||
/// function calls/returns and switching betweens stacks of different threads!
|
||||
/// We carry around the address of the `locals` buffer of the correct stack frame as a sanity
|
||||
/// chec to be able to catch some cases of using a dangling `Place`.
|
||||
/// check to be able to catch some cases of using a dangling `Place`.
|
||||
///
|
||||
/// This variant shall not be used for unsized types -- those must always live in memory.
|
||||
Local { local: mir::Local, offset: Option<Size>, locals_addr: usize },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! Manages the low-level pushing and popping of stack frames and the (de)allocation of local variables.
|
||||
//! For hadling of argument passing and return values, see the `call` module.
|
||||
//! For handling of argument passing and return values, see the `call` module.
|
||||
use std::cell::Cell;
|
||||
use std::{fmt, mem};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#![feature(trait_alias)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(yeet_expr)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub mod check_consts;
|
||||
|
|
|
@ -42,7 +42,7 @@ impl fmt::Display for BaseNString {
|
|||
}
|
||||
|
||||
// This trait just lets us reserve the exact right amount of space when doing fixed-length
|
||||
// case-insensitve encoding. Add any impls you need.
|
||||
// case-insensitive encoding. Add any impls you need.
|
||||
pub trait ToBaseN: Into<u128> {
|
||||
fn encoded_len(base: usize) -> usize;
|
||||
|
||||
|
|
|
@ -477,7 +477,7 @@ where
|
|||
// will know when we hit the state where previous_node == node.
|
||||
loop {
|
||||
// Back at the beginning, we can return. Note that we return the root state.
|
||||
// This is becuse for components being explored, we would otherwise get a
|
||||
// This is because for components being explored, we would otherwise get a
|
||||
// `node_state[n] = InCycleWith{ parent: n }` and that's wrong.
|
||||
if previous_node == node {
|
||||
return root_state;
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
//! or 16 bytes of the hash.
|
||||
//!
|
||||
//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`.
|
||||
//! `Hash64` and `Hash128` expose some utilty functions to encourage users to not extract the inner
|
||||
//! `Hash64` and `Hash128` expose some utility functions to encourage users to not extract the inner
|
||||
//! hash value as an integer type and accidentally apply varint encoding to it.
|
||||
//!
|
||||
//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct
|
||||
//! and decompose these types into constitutent pieces. The point of these types is only to
|
||||
//! and decompose these types into constituent pieces. The point of these types is only to
|
||||
//! connect the fact that they can only be produced by a `StableHasher` to their
|
||||
//! `Encode`/`Decode` impls.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ impl RegistryId {
|
|||
/// index within the registry. This panics if the current thread is not associated with this
|
||||
/// registry.
|
||||
///
|
||||
/// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused
|
||||
/// Note that there's a race possible where the identifier in `THREAD_DATA` could be reused
|
||||
/// so this can succeed from a different registry.
|
||||
#[cfg(parallel_compiler)]
|
||||
fn verify(self) -> usize {
|
||||
|
@ -50,7 +50,7 @@ struct ThreadData {
|
|||
}
|
||||
|
||||
thread_local! {
|
||||
/// A thread local which contains the identifer of `REGISTRY` but allows for faster access.
|
||||
/// A thread local which contains the identifier of `REGISTRY` but allows for faster access.
|
||||
/// It also holds the index of the current thread.
|
||||
static THREAD_DATA: ThreadData = const { ThreadData {
|
||||
registry_id: Cell::new(RegistryId(ptr::null())),
|
||||
|
@ -66,7 +66,7 @@ impl Registry {
|
|||
|
||||
/// Gets the registry associated with the current thread. Panics if there's no such registry.
|
||||
pub fn current() -> Self {
|
||||
REGISTRY.with(|registry| registry.get().cloned().expect("No assocated registry"))
|
||||
REGISTRY.with(|registry| registry.get().cloned().expect("No associated registry"))
|
||||
}
|
||||
|
||||
/// Registers the current thread with the registry so worker locals can be used on it.
|
||||
|
@ -92,7 +92,7 @@ impl Registry {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the identifer of this registry.
|
||||
/// Gets the identifier of this registry.
|
||||
fn id(&self) -> RegistryId {
|
||||
RegistryId(&*self.0)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
|||
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
|
||||
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
|
||||
rustc_incremental = { path = "../rustc_incremental" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_interface = { path = "../rustc_interface" }
|
||||
rustc_lint = { path = "../rustc_lint" }
|
||||
|
@ -72,6 +73,10 @@ ctrlc = "3.4.4"
|
|||
# tidy-alphabetical-start
|
||||
llvm = ['rustc_interface/llvm']
|
||||
max_level_info = ['rustc_log/max_level_info']
|
||||
rustc_randomized_layouts = [
|
||||
'rustc_index/rustc_randomized_layouts',
|
||||
'rustc_middle/rustc_randomized_layouts'
|
||||
]
|
||||
rustc_use_parallel_compiler = [
|
||||
'rustc_data_structures/rustc_use_parallel_compiler',
|
||||
'rustc_interface/rustc_use_parallel_compiler',
|
||||
|
|
|
@ -61,7 +61,6 @@ use rustc_session::lint::{Lint, LintId};
|
|||
use rustc_session::output::collect_crate_types;
|
||||
use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
|
||||
use rustc_span::source_map::FileLoader;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::FileName;
|
||||
use rustc_target::json::ToJson;
|
||||
use rustc_target::spec::{Target, TargetTriple};
|
||||
|
@ -777,16 +776,8 @@ fn print_crate_info(
|
|||
.config
|
||||
.iter()
|
||||
.filter_map(|&(name, value)| {
|
||||
// Note that crt-static is a specially recognized cfg
|
||||
// directive that's printed out here as part of
|
||||
// rust-lang/rust#37406, but in general the
|
||||
// `target_feature` cfg is gated under
|
||||
// rust-lang/rust#29717. For now this is just
|
||||
// specifically allowing the crt-static cfg and that's
|
||||
// it, this is intended to get into Cargo and then go
|
||||
// through to build scripts.
|
||||
if (name != sym::target_feature || value != Some(sym::crt_dash_static))
|
||||
&& !sess.is_nightly_build()
|
||||
// On stable, exclude unstable flags.
|
||||
if !sess.is_nightly_build()
|
||||
&& find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
|
||||
{
|
||||
return None;
|
||||
|
|
|
@ -44,7 +44,7 @@ where
|
|||
```
|
||||
The latter scenario encounters this error because `Foo::Assoc<'a>` could be
|
||||
implemented by a type that does not use the `'a` parameter, so there is no
|
||||
guarentee that `X::Assoc<'a>` actually uses `'a`.
|
||||
guarantee that `X::Assoc<'a>` actually uses `'a`.
|
||||
|
||||
To fix this we can pass a dummy parameter:
|
||||
```
|
||||
|
|
|
@ -479,7 +479,7 @@ pub struct Subdiag {
|
|||
/// - The `EmissionGuarantee`, which determines the type returned from `emit`.
|
||||
///
|
||||
/// Each constructed `Diag` must be consumed by a function such as `emit`,
|
||||
/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurrs if a `Diag`
|
||||
/// `cancel`, `delay_as_bug`, or `into_diag`. A panic occurs if a `Diag`
|
||||
/// is dropped without being consumed by one of these functions.
|
||||
///
|
||||
/// If there is some state in a downstream crate you would like to access in
|
||||
|
|
|
@ -2300,7 +2300,7 @@ impl HumanEmitter {
|
|||
// For example, for the following:
|
||||
// |
|
||||
// 2 - .await
|
||||
// 2 + (note the left over whitepsace)
|
||||
// 2 + (note the left over whitespace)
|
||||
// |
|
||||
// We really want
|
||||
// |
|
||||
|
|
|
@ -817,7 +817,7 @@ impl<'a> DiagCtxtHandle<'a> {
|
|||
);
|
||||
}
|
||||
// We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs`
|
||||
// can be used to create a backtrace at the stashing site insted of whenever the
|
||||
// can be used to create a backtrace at the stashing site instead of whenever the
|
||||
// diagnostic context is dropped and thus delayed bugs are emitted.
|
||||
Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
|
||||
DelayedBug => {
|
||||
|
|
|
@ -487,7 +487,7 @@ fn is_break_ty(val: &MdTree<'_>) -> bool {
|
|||
|| matches!(val, MdTree::PlainText(txt) if txt.trim().is_empty())
|
||||
}
|
||||
|
||||
/// Perform tranformations to text. This splits paragraphs, replaces patterns,
|
||||
/// Perform transformations to text. This splits paragraphs, replaces patterns,
|
||||
/// and corrects newlines.
|
||||
///
|
||||
/// To avoid allocating strings (and using a different heavier tt type), our
|
||||
|
|
|
@ -349,8 +349,10 @@ declare_features! (
|
|||
(unstable, adt_const_params, "1.56.0", Some(95174)),
|
||||
/// Allows defining an `#[alloc_error_handler]`.
|
||||
(unstable, alloc_error_handler, "1.29.0", Some(51540)),
|
||||
/// Allows trait methods with arbitrary self types.
|
||||
/// Allows inherent and trait methods with arbitrary self types.
|
||||
(unstable, arbitrary_self_types, "1.23.0", Some(44874)),
|
||||
/// Allows inherent and trait methods with arbitrary self types that are raw pointers.
|
||||
(unstable, arbitrary_self_types_pointers, "CURRENT_RUSTC_VERSION", Some(44874)),
|
||||
/// Enables experimental inline assembly support for additional architectures.
|
||||
(unstable, asm_experimental_arch, "1.58.0", Some(93335)),
|
||||
/// Allows using `label` operands in inline assembly.
|
||||
|
@ -585,7 +587,7 @@ declare_features! (
|
|||
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
|
||||
/// Allows use of x86 SHA512, SM3 and SM4 target-features and intrinsics
|
||||
(unstable, sha512_sm_x86, "CURRENT_RUSTC_VERSION", Some(126624)),
|
||||
/// Shortern the tail expression lifetime
|
||||
/// Shorten the tail expression lifetime
|
||||
(unstable, shorter_tail_lifetimes, "1.79.0", Some(123739)),
|
||||
/// Allows the use of SIMD types in functions declared in `extern` blocks.
|
||||
(unstable, simd_ffi, "1.0.0", Some(27731)),
|
||||
|
|
|
@ -1016,7 +1016,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
|
|||
sym::adt_const_params,
|
||||
)])
|
||||
}
|
||||
// Implments `ConstParamTy`, suggest adding the feature to enable.
|
||||
// Implements `ConstParamTy`, suggest adding the feature to enable.
|
||||
Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]),
|
||||
};
|
||||
if let Some(features) = may_suggest_feature {
|
||||
|
@ -1652,6 +1652,13 @@ fn check_fn_or_method<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// The `arbitrary_self_types_pointers` feature implies `arbitrary_self_types`.
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum ArbitrarySelfTypesLevel {
|
||||
Basic, // just arbitrary_self_types
|
||||
WithPointers, // both arbitrary_self_types and arbitrary_self_types_pointers
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(wfcx))]
|
||||
fn check_method_receiver<'tcx>(
|
||||
wfcx: &WfCheckingCtxt<'_, 'tcx>,
|
||||
|
@ -1684,14 +1691,27 @@ fn check_method_receiver<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
if tcx.features().arbitrary_self_types {
|
||||
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
|
||||
// Report error; `arbitrary_self_types` was enabled.
|
||||
return Err(tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty }));
|
||||
}
|
||||
let arbitrary_self_types_level = if tcx.features().arbitrary_self_types_pointers {
|
||||
Some(ArbitrarySelfTypesLevel::WithPointers)
|
||||
} else if tcx.features().arbitrary_self_types {
|
||||
Some(ArbitrarySelfTypesLevel::Basic)
|
||||
} else {
|
||||
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, false) {
|
||||
return Err(if receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
|
||||
None
|
||||
};
|
||||
|
||||
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
|
||||
return Err(match arbitrary_self_types_level {
|
||||
// Wherever possible, emit a message advising folks that the features
|
||||
// `arbitrary_self_types` or `arbitrary_self_types_pointers` might
|
||||
// have helped.
|
||||
None if receiver_is_valid(
|
||||
wfcx,
|
||||
span,
|
||||
receiver_ty,
|
||||
self_ty,
|
||||
Some(ArbitrarySelfTypesLevel::Basic),
|
||||
) =>
|
||||
{
|
||||
// Report error; would have worked with `arbitrary_self_types`.
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
|
@ -1699,25 +1719,49 @@ fn check_method_receiver<'tcx>(
|
|||
span,
|
||||
format!(
|
||||
"`{receiver_ty}` cannot be used as the type of `self` without \
|
||||
the `arbitrary_self_types` feature",
|
||||
the `arbitrary_self_types` feature",
|
||||
),
|
||||
)
|
||||
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
|
||||
.emit()
|
||||
} else {
|
||||
// Report error; would not have worked with `arbitrary_self_types`.
|
||||
}
|
||||
None | Some(ArbitrarySelfTypesLevel::Basic)
|
||||
if receiver_is_valid(
|
||||
wfcx,
|
||||
span,
|
||||
receiver_ty,
|
||||
self_ty,
|
||||
Some(ArbitrarySelfTypesLevel::WithPointers),
|
||||
) =>
|
||||
{
|
||||
// Report error; would have worked with `arbitrary_self_types_pointers`.
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
sym::arbitrary_self_types_pointers,
|
||||
span,
|
||||
format!(
|
||||
"`{receiver_ty}` cannot be used as the type of `self` without \
|
||||
the `arbitrary_self_types_pointers` feature",
|
||||
),
|
||||
)
|
||||
.with_help(fluent::hir_analysis_invalid_receiver_ty_help)
|
||||
.emit()
|
||||
}
|
||||
_ =>
|
||||
// Report error; would not have worked with `arbitrary_self_types[_pointers]`.
|
||||
{
|
||||
tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
|
||||
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
|
||||
/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
|
||||
/// strict: `receiver_ty` must implement `Receiver` and directly implement
|
||||
/// `Deref<Target = self_ty>`.
|
||||
/// through a `*const/mut T` raw pointer if `arbitrary_self_types_pointers` is also enabled.
|
||||
/// If neither feature is enabled, the requirements are more strict: `receiver_ty` must implement
|
||||
/// `Receiver` and directly implement `Deref<Target = self_ty>`.
|
||||
///
|
||||
/// N.B., there are cases this function returns `true` but causes an error to be emitted,
|
||||
/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
|
||||
|
@ -1727,7 +1771,7 @@ fn receiver_is_valid<'tcx>(
|
|||
span: Span,
|
||||
receiver_ty: Ty<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
arbitrary_self_types_enabled: bool,
|
||||
arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
|
||||
) -> bool {
|
||||
let infcx = wfcx.infcx;
|
||||
let tcx = wfcx.tcx();
|
||||
|
@ -1745,8 +1789,8 @@ fn receiver_is_valid<'tcx>(
|
|||
|
||||
let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
|
||||
|
||||
// The `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`.
|
||||
if arbitrary_self_types_enabled {
|
||||
// The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
|
||||
if arbitrary_self_types_enabled == Some(ArbitrarySelfTypesLevel::WithPointers) {
|
||||
autoderef = autoderef.include_raw_pointers();
|
||||
}
|
||||
|
||||
|
@ -1772,7 +1816,7 @@ fn receiver_is_valid<'tcx>(
|
|||
|
||||
// Without `feature(arbitrary_self_types)`, we require that each step in the
|
||||
// deref chain implement `receiver`.
|
||||
if !arbitrary_self_types_enabled {
|
||||
if arbitrary_self_types_enabled.is_none() {
|
||||
if !receiver_is_implemented(
|
||||
wfcx,
|
||||
receiver_trait_def_id,
|
||||
|
|
|
@ -219,7 +219,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
|
|||
// Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
|
||||
// pointers. This is enforced here: we only allow impls for references, raw pointers, and things
|
||||
// that are effectively repr(transparent) newtypes around types that already hav a
|
||||
// DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some
|
||||
// DispatchedFromDyn impl. We cannot literally use repr(transparent) on those types since some
|
||||
// of them support an allocator, but we ensure that for the cases where the type implements this
|
||||
// trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
|
||||
// in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
|
||||
|
|
|
@ -1037,7 +1037,7 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
|
|||
|
||||
/// Check the uniqueness of fields in a struct variant, and recursively
|
||||
/// check the nested fields if it is an unnamed field with type of an
|
||||
/// annoymous adt.
|
||||
/// anonymous adt.
|
||||
fn check_field(&mut self, field: &hir::FieldDef<'_>) {
|
||||
if field.ident.name != kw::Underscore {
|
||||
self.check_field_decl(field.ident, field.span.into());
|
||||
|
@ -1491,7 +1491,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
|||
Some(ty) => {
|
||||
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
|
||||
// Typeck doesn't expect erased regions to be returned from `type_of`.
|
||||
// This is a heuristic approach. If the scope has region paramters,
|
||||
// This is a heuristic approach. If the scope has region parameters,
|
||||
// we should change fn_sig's lifetime from `ReErased` to `ReError`,
|
||||
// otherwise to `ReStatic`.
|
||||
let has_region_params = generics.params.iter().any(|param| match param.kind {
|
||||
|
|
|
@ -529,7 +529,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
/// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings.
|
||||
///
|
||||
/// FIXME(const_generics): This is a temporary and semi-artifical restriction until the
|
||||
/// FIXME(const_generics): This is a temporary and semi-artificial restriction until the
|
||||
/// arrival of *generic const generics*[^1].
|
||||
///
|
||||
/// It might actually be possible that we can already support early-bound generic params
|
||||
|
|
|
@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
return;
|
||||
};
|
||||
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
|
||||
if sugg.is_empty() {
|
||||
return;
|
||||
};
|
||||
diag.multipart_suggestion(
|
||||
format!(
|
||||
"alternatively use a blanket implementation to implement `{of_trait_name}` for \
|
||||
|
@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
|
||||
// FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
|
||||
// and suggest `Trait0<Ty = impl Trait1>`.
|
||||
// Functions are found in three different contexts.
|
||||
// 1. Independent functions
|
||||
// 2. Functions inside trait blocks
|
||||
// 3. Functions inside impl blocks
|
||||
let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
|
||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
|
||||
(sig, generics, None)
|
||||
|
@ -180,6 +181,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
owner_id,
|
||||
..
|
||||
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
|
||||
hir::Node::ImplItem(hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(sig, _),
|
||||
generics,
|
||||
owner_id,
|
||||
..
|
||||
}) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
|
||||
_ => return false,
|
||||
};
|
||||
let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
|
||||
|
@ -187,6 +194,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
};
|
||||
let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
|
||||
let mut is_downgradable = true;
|
||||
|
||||
// Check if trait object is safe for suggesting dynamic dispatch.
|
||||
let is_object_safe = match self_ty.kind {
|
||||
hir::TyKind::TraitObject(objects, ..) => {
|
||||
objects.iter().all(|(o, _)| match o.trait_ref.path.res {
|
||||
|
@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let borrowed = matches!(
|
||||
tcx.parent_hir_node(self_ty.hir_id),
|
||||
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
|
||||
);
|
||||
|
||||
// Suggestions for function return type.
|
||||
if let hir::FnRetTy::Return(ty) = sig.decl.output
|
||||
&& ty.hir_id == self_ty.hir_id
|
||||
&& ty.peel_refs().hir_id == self_ty.hir_id
|
||||
{
|
||||
let pre = if !is_object_safe {
|
||||
format!("`{trait_name}` is not object safe, ")
|
||||
|
@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
"{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
|
||||
single underlying type",
|
||||
);
|
||||
|
||||
diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
|
||||
|
||||
// Suggest `Box<dyn Trait>` for return type
|
||||
if is_object_safe {
|
||||
diag.multipart_suggestion_verbose(
|
||||
"alternatively, you can return an owned trait object",
|
||||
// If the return type is `&Trait`, we don't want
|
||||
// the ampersand to be displayed in the `Box<dyn Trait>`
|
||||
// suggestion.
|
||||
let suggestion = if borrowed {
|
||||
vec![(ty.span, format!("Box<dyn {trait_name}>"))]
|
||||
} else {
|
||||
vec![
|
||||
(ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
|
||||
(ty.span.shrink_to_hi(), ">".to_string()),
|
||||
],
|
||||
]
|
||||
};
|
||||
|
||||
diag.multipart_suggestion_verbose(
|
||||
"alternatively, you can return an owned trait object",
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if is_downgradable {
|
||||
|
@ -230,24 +258,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Suggestions for function parameters.
|
||||
for ty in sig.decl.inputs {
|
||||
if ty.hir_id != self_ty.hir_id {
|
||||
if ty.peel_refs().hir_id != self_ty.hir_id {
|
||||
continue;
|
||||
}
|
||||
let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
|
||||
if !sugg.is_empty() {
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("use a new generic type parameter, constrained by `{trait_name}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.multipart_suggestion_verbose(
|
||||
"you can also use an opaque type, but users won't be able to specify the type \
|
||||
parameter when calling the `fn`, having to rely exclusively on type inference",
|
||||
impl_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!("use a new generic type parameter, constrained by `{trait_name}`"),
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.multipart_suggestion_verbose(
|
||||
"you can also use an opaque type, but users won't be able to specify the type \
|
||||
parameter when calling the `fn`, having to rely exclusively on type inference",
|
||||
impl_sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
if !is_object_safe {
|
||||
diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
|
||||
if is_downgradable {
|
||||
|
@ -255,14 +283,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
diag.downgrade_to_delayed_bug();
|
||||
}
|
||||
} else {
|
||||
// No ampersand in suggestion if it's borrowed already
|
||||
let (dyn_str, paren_dyn_str) =
|
||||
if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
|
||||
|
||||
let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
|
||||
// There are more than one trait bound, we need surrounding parentheses.
|
||||
vec![
|
||||
(self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
|
||||
(self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
|
||||
(self_ty.span.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
} else {
|
||||
vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
|
||||
vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
|
||||
};
|
||||
diag.multipart_suggestion_verbose(
|
||||
format!(
|
||||
|
|
|
@ -986,7 +986,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
/// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where
|
||||
/// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`.
|
||||
/// For the latter case, we report ambiguity.
|
||||
/// While desirable to support, the implemention would be non-trivial. Tracked in [#22519].
|
||||
/// While desirable to support, the implementation would be non-trivial. Tracked in [#22519].
|
||||
///
|
||||
/// At the time of writing, *inherent associated types* are also resolved here. This however
|
||||
/// is [problematic][iat]. A proper implementation would be as non-trivial as the one
|
||||
|
|
|
@ -503,18 +503,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
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.
|
||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
call_expr.span,
|
||||
expected,
|
||||
fn_sig.output(),
|
||||
fn_sig.inputs(),
|
||||
);
|
||||
self.check_argument_types(
|
||||
call_expr.span,
|
||||
call_expr,
|
||||
fn_sig.inputs(),
|
||||
expected_arg_tys,
|
||||
fn_sig.output(),
|
||||
expected,
|
||||
arg_exprs,
|
||||
fn_sig.c_variadic,
|
||||
TupleArgumentsFlag::DontTupleArguments,
|
||||
|
@ -866,19 +860,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// don't know the full details yet (`Fn` vs `FnMut` etc), but we
|
||||
// do know the types expected for each argument and the return
|
||||
// type.
|
||||
|
||||
let expected_arg_tys = self.expected_inputs_for_expected_output(
|
||||
call_expr.span,
|
||||
expected,
|
||||
fn_sig.output(),
|
||||
fn_sig.inputs(),
|
||||
);
|
||||
|
||||
self.check_argument_types(
|
||||
call_expr.span,
|
||||
call_expr,
|
||||
fn_sig.inputs(),
|
||||
expected_arg_tys,
|
||||
fn_sig.output(),
|
||||
expected,
|
||||
arg_exprs,
|
||||
fn_sig.c_variadic,
|
||||
TupleArgumentsFlag::TupleArguments,
|
||||
|
|
|
@ -650,7 +650,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
// cannot distinguish. This would cause us to erroneously discard a cast which will
|
||||
// lead to a borrowck error like #113257.
|
||||
// We still did a coercion above to unify inference variables for `ptr as _` casts.
|
||||
// This does cause us to miss some trivial casts in the trival cast lint.
|
||||
// This does cause us to miss some trivial casts in the trivial cast lint.
|
||||
debug!(" -> PointerCast");
|
||||
} else {
|
||||
self.trivial_cast_lint(fcx);
|
||||
|
|
|
@ -1673,15 +1673,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) {
|
||||
let tcx = self.tcx;
|
||||
|
||||
let expected_inputs =
|
||||
self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]);
|
||||
let adt_ty_hint = if let Some(expected_inputs) = expected_inputs {
|
||||
expected_inputs.get(0).cloned().unwrap_or(adt_ty)
|
||||
} else {
|
||||
adt_ty
|
||||
};
|
||||
// re-link the regions that EIfEO can erase.
|
||||
self.demand_eqtype(span, adt_ty_hint, adt_ty);
|
||||
let adt_ty = self.resolve_vars_with_obligations(adt_ty);
|
||||
let adt_ty_hint = expected.only_has_type(self).and_then(|expected| {
|
||||
self.fudge_inference_if_ok(|| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?;
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
Ok(self.resolve_vars_if_possible(adt_ty))
|
||||
})
|
||||
.ok()
|
||||
});
|
||||
if let Some(adt_ty_hint) = adt_ty_hint {
|
||||
// re-link the variables that the fudging above can create.
|
||||
self.demand_eqtype(span, adt_ty_hint, adt_ty);
|
||||
}
|
||||
|
||||
let ty::Adt(adt, args) = adt_ty.kind() else {
|
||||
span_bug!(span, "non-ADT passed to check_expr_struct_fields");
|
||||
|
|
|
@ -20,7 +20,6 @@ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryRespons
|
|||
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
||||
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||
use rustc_middle::ty::{
|
||||
|
@ -36,7 +35,7 @@ use rustc_span::Span;
|
|||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
|
||||
self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
@ -689,42 +688,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
vec![ty_error; len]
|
||||
}
|
||||
|
||||
/// Unifies the output type with the expected type early, for more coercions
|
||||
/// and forward type information on the input expressions.
|
||||
#[instrument(skip(self, call_span), level = "debug")]
|
||||
pub(crate) fn expected_inputs_for_expected_output(
|
||||
&self,
|
||||
call_span: Span,
|
||||
expected_ret: Expectation<'tcx>,
|
||||
formal_ret: Ty<'tcx>,
|
||||
formal_args: &[Ty<'tcx>],
|
||||
) -> Option<Vec<Ty<'tcx>>> {
|
||||
let formal_ret = self.resolve_vars_with_obligations(formal_ret);
|
||||
let ret_ty = expected_ret.only_has_type(self)?;
|
||||
|
||||
let expect_args = self
|
||||
.fudge_inference_if_ok(|| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
|
||||
// Attempt to apply a subtyping relationship between the formal
|
||||
// return type (likely containing type variables if the function
|
||||
// is polymorphic) and the expected return type.
|
||||
// No argument expectations are produced if unification fails.
|
||||
let origin = self.misc(call_span);
|
||||
ocx.sup(&origin, self.param_env, ret_ty, formal_ret)?;
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
|
||||
// Record all the argument types, with the args
|
||||
// produced from the above subtyping unification.
|
||||
Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret);
|
||||
expect_args
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_lang_item_path(
|
||||
&self,
|
||||
lang_item: hir::LangItem,
|
||||
|
|
|
@ -17,6 +17,7 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
|||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
@ -25,7 +26,7 @@ use rustc_span::symbol::{kw, Ident};
|
|||
use rustc_span::{sym, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
|
||||
use tracing::debug;
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
|
@ -124,6 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
if let Err(guar) = has_error {
|
||||
let err_inputs = self.err_args(args_no_rcvr.len(), guar);
|
||||
let err_output = Ty::new_error(self.tcx, guar);
|
||||
|
||||
let err_inputs = match tuple_arguments {
|
||||
DontTupleArguments => err_inputs,
|
||||
|
@ -134,28 +136,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
sp,
|
||||
expr,
|
||||
&err_inputs,
|
||||
None,
|
||||
err_output,
|
||||
NoExpectation,
|
||||
args_no_rcvr,
|
||||
false,
|
||||
tuple_arguments,
|
||||
method.ok().map(|method| method.def_id),
|
||||
);
|
||||
return Ty::new_error(self.tcx, guar);
|
||||
return err_output;
|
||||
}
|
||||
|
||||
let method = method.unwrap();
|
||||
// HACK(eddyb) ignore self in the definition (see above).
|
||||
let expected_input_tys = self.expected_inputs_for_expected_output(
|
||||
sp,
|
||||
expected,
|
||||
method.sig.output(),
|
||||
&method.sig.inputs()[1..],
|
||||
);
|
||||
self.check_argument_types(
|
||||
sp,
|
||||
expr,
|
||||
&method.sig.inputs()[1..],
|
||||
expected_input_tys,
|
||||
method.sig.output(),
|
||||
expected,
|
||||
args_no_rcvr,
|
||||
method.sig.c_variadic,
|
||||
tuple_arguments,
|
||||
|
@ -175,8 +172,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
call_expr: &'tcx hir::Expr<'tcx>,
|
||||
// Types (as defined in the *signature* of the target function)
|
||||
formal_input_tys: &[Ty<'tcx>],
|
||||
// More specific expected types, after unifying with caller output types
|
||||
expected_input_tys: Option<Vec<Ty<'tcx>>>,
|
||||
formal_output: Ty<'tcx>,
|
||||
// Expected output from the parent expression or statement
|
||||
expectation: Expectation<'tcx>,
|
||||
// The expressions for each provided argument
|
||||
provided_args: &'tcx [hir::Expr<'tcx>],
|
||||
// Whether the function is variadic, for example when imported from C
|
||||
|
@ -210,6 +208,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
// First, let's unify the formal method signature with the expectation eagerly.
|
||||
// We use this to guide coercion inference; it's output is "fudged" which means
|
||||
// any remaining type variables are assigned to new, unrelated variables. This
|
||||
// is because the inference guidance here is only speculative.
|
||||
let formal_output = self.resolve_vars_with_obligations(formal_output);
|
||||
let expected_input_tys: Option<Vec<_>> = expectation
|
||||
.only_has_type(self)
|
||||
.and_then(|expected_output| {
|
||||
self.fudge_inference_if_ok(|| {
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
|
||||
// Attempt to apply a subtyping relationship between the formal
|
||||
// return type (likely containing type variables if the function
|
||||
// is polymorphic) and the expected return type.
|
||||
// No argument expectations are produced if unification fails.
|
||||
let origin = self.misc(call_span);
|
||||
ocx.sup(&origin, self.param_env, expected_output, formal_output)?;
|
||||
if !ocx.select_where_possible().is_empty() {
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
|
||||
// Record all the argument types, with the args
|
||||
// produced from the above subtyping unification.
|
||||
Ok(Some(
|
||||
formal_input_tys
|
||||
.iter()
|
||||
.map(|&ty| self.resolve_vars_if_possible(ty))
|
||||
.collect(),
|
||||
))
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut err_code = E0061;
|
||||
|
||||
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
|
||||
|
@ -292,21 +324,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let coerce_error =
|
||||
self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err();
|
||||
|
||||
if coerce_error.is_some() {
|
||||
return Compatibility::Incompatible(coerce_error);
|
||||
}
|
||||
|
||||
// 3. Check if the formal type is a supertype of the checked one
|
||||
// and register any such obligations for future type checks
|
||||
let supertype_error = self.at(&self.misc(provided_arg.span), self.param_env).sup(
|
||||
// 3. Check if the formal type is actually equal to the checked one
|
||||
// and register any such obligations for future type checks.
|
||||
let formal_ty_error = self.at(&self.misc(provided_arg.span), self.param_env).eq(
|
||||
DefineOpaqueTypes::Yes,
|
||||
formal_input_ty,
|
||||
coerced_ty,
|
||||
);
|
||||
|
||||
// If neither check failed, the types are compatible
|
||||
match supertype_error {
|
||||
match formal_ty_error {
|
||||
Ok(InferOk { obligations, value: () }) => {
|
||||
self.register_predicates(obligations);
|
||||
Compatibility::Compatible
|
||||
|
|
|
@ -249,7 +249,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Returns a set of generic parameters for the method *receiver* where all type and region
|
||||
/// parameters are instantiated with fresh variables. This generic paramters does not include any
|
||||
/// parameters are instantiated with fresh variables. This generic parameters does not include any
|
||||
/// parameters declared on the method itself.
|
||||
///
|
||||
/// Note that this generic parameters may include late-bound regions from the impl level. If so,
|
||||
|
@ -375,7 +375,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
IsMethodCall::Yes,
|
||||
);
|
||||
|
||||
// Create generic paramters for early-bound lifetime parameters,
|
||||
// Create generic parameters for early-bound lifetime parameters,
|
||||
// combining parameters from the type and those from the method.
|
||||
assert_eq!(generics.parent_count, parent_args.len());
|
||||
|
||||
|
@ -546,7 +546,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args);
|
||||
|
||||
// Instantiate the bounds on the method with the
|
||||
// type/early-bound-regions instatiations performed. There can
|
||||
// type/early-bound-regions instantiations performed. There can
|
||||
// be no late-bound regions appearing here.
|
||||
let def_id = pick.item.def_id;
|
||||
let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args);
|
||||
|
|
|
@ -403,7 +403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
mode,
|
||||
}));
|
||||
} else if bad_ty.reached_raw_pointer
|
||||
&& !self.tcx.features().arbitrary_self_types
|
||||
&& !self.tcx.features().arbitrary_self_types_pointers
|
||||
&& !self.tcx.sess.at_least_rust_2018()
|
||||
{
|
||||
// this case used to be allowed by the compiler,
|
||||
|
|
|
@ -228,7 +228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// coroutine bodies can't borrow from their parent closure. To fix this,
|
||||
// we force the inner coroutine to also be `move`. This only matters for
|
||||
// coroutine-closures that are `move` since otherwise they themselves will
|
||||
// be borrowing from the outer environment, so there's no self-borrows occuring.
|
||||
// be borrowing from the outer environment, so there's no self-borrows occurring.
|
||||
if let UpvarArgs::Coroutine(..) = args
|
||||
&& let hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) =
|
||||
self.tcx.coroutine_kind(closure_def_id).expect("coroutine should have kind")
|
||||
|
|
|
@ -20,4 +20,5 @@ nightly = [
|
|||
"dep:rustc_macros",
|
||||
"rustc_index_macros/nightly",
|
||||
]
|
||||
rustc_randomized_layouts = []
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -33,8 +33,19 @@ pub use vec::IndexVec;
|
|||
///
|
||||
/// </div>
|
||||
#[macro_export]
|
||||
#[cfg(not(feature = "rustc_randomized_layouts"))]
|
||||
macro_rules! static_assert_size {
|
||||
($ty:ty, $size:expr) => {
|
||||
const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()];
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[cfg(feature = "rustc_randomized_layouts")]
|
||||
macro_rules! static_assert_size {
|
||||
($ty:ty, $size:expr) => {
|
||||
// no effect other than using the statements.
|
||||
// struct sizes are not deterministic under randomized layouts
|
||||
const _: (usize, usize) = ($size, ::std::mem::size_of::<$ty>());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
query_state,
|
||||
|tcx, param_env, query_state| {
|
||||
// FIXME(#118965): We don't canonicalize the static lifetimes that appear in the
|
||||
// `param_env` beacause they are treated differently by trait selection.
|
||||
// `param_env` because they are treated differently by trait selection.
|
||||
Canonicalizer::canonicalize(
|
||||
param_env,
|
||||
None,
|
||||
|
|
|
@ -213,7 +213,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
/// ```
|
||||
///
|
||||
/// As indicating in the comments above, each of those references
|
||||
/// is (in the compiler) basically generic paramters (`args`)
|
||||
/// is (in the compiler) basically generic parameters (`args`)
|
||||
/// applied to the type of a suitable `def_id` (which identifies
|
||||
/// `Foo1` or `Foo2`).
|
||||
///
|
||||
|
|
|
@ -153,7 +153,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
// During coherence, opaque types should be treated as *possibly*
|
||||
// equal to any other type (except for possibly itself). This is an
|
||||
// extremely heavy hammer, but can be relaxed in a fowards-compatible
|
||||
// extremely heavy hammer, but can be relaxed in a forwards-compatible
|
||||
// way later.
|
||||
(&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => {
|
||||
relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
|
||||
|
|
|
@ -120,7 +120,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
} else {
|
||||
// NOTE: The `instantiation_variance` is not the same variance as
|
||||
// used by the relation. When instantiating `b`, `target_is_expected`
|
||||
// is flipped and the `instantion_variance` is also flipped. To
|
||||
// is flipped and the `instantiation_variance` is also flipped. To
|
||||
// constrain the `generalized_ty` while using the original relation,
|
||||
// we therefore only have to flip the arguments.
|
||||
//
|
||||
|
|
|
@ -435,7 +435,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
escape_dep_filename(&file.prefer_local().to_string())
|
||||
};
|
||||
|
||||
// The entries will be used to declare dependencies beween files in a
|
||||
// The entries will be used to declare dependencies between files in a
|
||||
// Makefile-like output, so the iteration order does not matter.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let extra_tracked_files =
|
||||
|
|
|
@ -783,6 +783,9 @@ lint_tykind = usage of `ty::TyKind`
|
|||
lint_tykind_kind = usage of `ty::TyKind::<kind>`
|
||||
.suggestion = try using `ty::<kind>` directly
|
||||
|
||||
lint_type_ir_inherent_usage = do not use `rustc_type_ir::inherent` unless you're inside of the trait solver
|
||||
.note = the method or struct you're looking for is likely defined somewhere else downstream in the compiler
|
||||
|
||||
lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::ManuallyDrop` instead of the inner value does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
||||
|
|
|
@ -267,7 +267,7 @@ pub(super) fn unexpected_cfg_value(
|
|||
// encouraged to do so.
|
||||
let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name)
|
||||
// Except when working on rustc or the standard library itself, in which case we want to
|
||||
// suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a
|
||||
// suggest adding these cfgs to the "normal" place because of bootstrapping reasons. As a
|
||||
// basic heuristic, we use the "cheat" unstable feature enable method and the
|
||||
// non-ui-testing enabled option.
|
||||
|| (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::cell::LazyCell;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
use rustc_middle::ty::relate::{
|
||||
structurally_relate_consts, structurally_relate_tys, Relate, RelateResult, TypeRelation,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
||||
use crate::{fluent_generated as fluent, LateContext, LateLintPass};
|
||||
|
||||
|
@ -119,20 +129,41 @@ impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
|
||||
enum ParamKind {
|
||||
// Early-bound var.
|
||||
Early(Symbol, u32),
|
||||
// Late-bound var on function, not within a binder. We can capture these.
|
||||
Free(DefId, Symbol),
|
||||
// Late-bound var in a binder. We can't capture these yet.
|
||||
Late,
|
||||
}
|
||||
|
||||
fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
|
||||
let sig = tcx.fn_sig(parent_def_id).instantiate_identity();
|
||||
|
||||
let mut in_scope_parameters = FxIndexSet::default();
|
||||
let mut in_scope_parameters = FxIndexMap::default();
|
||||
// Populate the in_scope_parameters list first with all of the generics in scope
|
||||
let mut current_def_id = Some(parent_def_id.to_def_id());
|
||||
while let Some(def_id) = current_def_id {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
for param in &generics.own_params {
|
||||
in_scope_parameters.insert(param.def_id);
|
||||
in_scope_parameters.insert(param.def_id, ParamKind::Early(param.name, param.index));
|
||||
}
|
||||
current_def_id = generics.parent;
|
||||
}
|
||||
|
||||
for bound_var in sig.bound_vars() {
|
||||
let ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, name)) = bound_var
|
||||
else {
|
||||
span_bug!(tcx.def_span(parent_def_id), "unexpected non-lifetime binder on fn sig");
|
||||
};
|
||||
|
||||
in_scope_parameters.insert(def_id, ParamKind::Free(def_id, name));
|
||||
}
|
||||
|
||||
let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig);
|
||||
|
||||
// Then visit the signature to walk through all the binders (incl. the late-bound
|
||||
// vars on the function itself, which we need to count too).
|
||||
sig.visit_with(&mut VisitOpaqueTypes {
|
||||
|
@ -140,21 +171,45 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
|
|||
parent_def_id,
|
||||
in_scope_parameters,
|
||||
seen: Default::default(),
|
||||
// Lazily compute these two, since they're likely a bit expensive.
|
||||
variances: LazyCell::new(|| {
|
||||
let mut functional_variances = FunctionalVariances {
|
||||
tcx: tcx,
|
||||
variances: FxHashMap::default(),
|
||||
ambient_variance: ty::Covariant,
|
||||
generics: tcx.generics_of(parent_def_id),
|
||||
};
|
||||
functional_variances.relate(sig, sig).unwrap();
|
||||
functional_variances.variances
|
||||
}),
|
||||
outlives_env: LazyCell::new(|| {
|
||||
let param_env = tcx.param_env(parent_def_id);
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
|
||||
let implied_bounds =
|
||||
infcx.implied_bounds_tys_compat(param_env, parent_def_id, &assumed_wf_tys, false);
|
||||
OutlivesEnvironment::with_bounds(param_env, implied_bounds)
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
struct VisitOpaqueTypes<'tcx> {
|
||||
struct VisitOpaqueTypes<'tcx, VarFn, OutlivesFn> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
parent_def_id: LocalDefId,
|
||||
in_scope_parameters: FxIndexSet<DefId>,
|
||||
in_scope_parameters: FxIndexMap<DefId, ParamKind>,
|
||||
variances: LazyCell<FxHashMap<DefId, ty::Variance>, VarFn>,
|
||||
outlives_env: LazyCell<OutlivesEnvironment<'tcx>, OutlivesFn>,
|
||||
seen: FxIndexSet<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
t: &ty::Binder<'tcx, T>,
|
||||
) -> Self::Result {
|
||||
impl<'tcx, VarFn, OutlivesFn> TypeVisitor<TyCtxt<'tcx>>
|
||||
for VisitOpaqueTypes<'tcx, VarFn, OutlivesFn>
|
||||
where
|
||||
VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>,
|
||||
OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
|
||||
{
|
||||
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
|
||||
// When we get into a binder, we need to add its own bound vars to the scope.
|
||||
let mut added = vec![];
|
||||
for arg in t.bound_vars() {
|
||||
|
@ -163,8 +218,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
|||
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
|
||||
| ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
|
||||
added.push(def_id);
|
||||
let unique = self.in_scope_parameters.insert(def_id);
|
||||
assert!(unique);
|
||||
let unique = self.in_scope_parameters.insert(def_id, ParamKind::Late);
|
||||
assert_eq!(unique, None);
|
||||
}
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
|
@ -184,7 +239,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
if !t.has_aliases() {
|
||||
return;
|
||||
}
|
||||
|
@ -207,89 +262,126 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
|||
&& let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
|
||||
&& parent_def_id == self.parent_def_id
|
||||
{
|
||||
// Compute the set of args that are captured by the opaque...
|
||||
let mut captured = FxIndexSet::default();
|
||||
let variances = self.tcx.variances_of(opaque_def_id);
|
||||
let mut current_def_id = Some(opaque_def_id.to_def_id());
|
||||
while let Some(def_id) = current_def_id {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
for param in &generics.own_params {
|
||||
// A param is captured if it's invariant.
|
||||
if variances[param.index as usize] != ty::Invariant {
|
||||
continue;
|
||||
}
|
||||
// We need to turn all `ty::Param`/`ConstKind::Param` and
|
||||
// `ReEarlyParam`/`ReBound` into def ids.
|
||||
captured.insert(extract_def_id_from_arg(
|
||||
self.tcx,
|
||||
generics,
|
||||
opaque_ty.args[param.index as usize],
|
||||
));
|
||||
}
|
||||
current_def_id = generics.parent;
|
||||
}
|
||||
|
||||
// Compute the set of in scope params that are not captured. Get their spans,
|
||||
// since that's all we really care about them for emitting the diagnostic.
|
||||
let uncaptured_spans: Vec<_> = self
|
||||
.in_scope_parameters
|
||||
.iter()
|
||||
.filter(|def_id| !captured.contains(*def_id))
|
||||
.map(|def_id| self.tcx.def_span(def_id))
|
||||
.collect();
|
||||
|
||||
let opaque_span = self.tcx.def_span(opaque_def_id);
|
||||
let new_capture_rules =
|
||||
opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
|
||||
|
||||
// If we have uncaptured args, and if the opaque doesn't already have
|
||||
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
|
||||
if !new_capture_rules
|
||||
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
|
||||
&& !uncaptured_spans.is_empty()
|
||||
{
|
||||
let suggestion = if let Ok(snippet) =
|
||||
self.tcx.sess.source_map().span_to_snippet(opaque_span)
|
||||
&& snippet.starts_with("impl ")
|
||||
{
|
||||
let (lifetimes, others): (Vec<_>, Vec<_>) = captured
|
||||
.into_iter()
|
||||
.partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam);
|
||||
// Take all lifetime params first, then all others (ty/ct).
|
||||
let generics: Vec<_> = lifetimes
|
||||
.into_iter()
|
||||
.chain(others)
|
||||
.map(|def_id| self.tcx.item_name(def_id).to_string())
|
||||
.collect();
|
||||
// Make sure that we're not trying to name any APITs
|
||||
if generics.iter().all(|name| !name.starts_with("impl ")) {
|
||||
Some((
|
||||
format!(" + use<{}>", generics.join(", ")),
|
||||
opaque_span.shrink_to_hi(),
|
||||
))
|
||||
// Compute the set of args that are captured by the opaque...
|
||||
let mut captured = FxIndexSet::default();
|
||||
let mut captured_regions = FxIndexSet::default();
|
||||
let variances = self.tcx.variances_of(opaque_def_id);
|
||||
let mut current_def_id = Some(opaque_def_id.to_def_id());
|
||||
while let Some(def_id) = current_def_id {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
for param in &generics.own_params {
|
||||
// A param is captured if it's invariant.
|
||||
if variances[param.index as usize] != ty::Invariant {
|
||||
continue;
|
||||
}
|
||||
|
||||
let arg = opaque_ty.args[param.index as usize];
|
||||
// We need to turn all `ty::Param`/`ConstKind::Param` and
|
||||
// `ReEarlyParam`/`ReBound` into def ids.
|
||||
captured.insert(extract_def_id_from_arg(self.tcx, generics, arg));
|
||||
|
||||
captured_regions.extend(arg.as_region());
|
||||
}
|
||||
current_def_id = generics.parent;
|
||||
}
|
||||
|
||||
// Compute the set of in scope params that are not captured.
|
||||
let mut uncaptured_args: FxIndexSet<_> = self
|
||||
.in_scope_parameters
|
||||
.iter()
|
||||
.filter(|&(def_id, _)| !captured.contains(def_id))
|
||||
.collect();
|
||||
// Remove the set of lifetimes that are in-scope that outlive some other captured
|
||||
// lifetime and are contravariant (i.e. covariant in argument position).
|
||||
uncaptured_args.retain(|&(def_id, kind)| {
|
||||
let Some(ty::Bivariant | ty::Contravariant) = self.variances.get(def_id) else {
|
||||
// Keep all covariant/invariant args. Also if variance is `None`,
|
||||
// then that means it's either not a lifetime, or it didn't show up
|
||||
// anywhere in the signature.
|
||||
return true;
|
||||
};
|
||||
// We only computed variance of lifetimes...
|
||||
debug_assert_matches!(self.tcx.def_kind(def_id), DefKind::LifetimeParam);
|
||||
let uncaptured = match *kind {
|
||||
ParamKind::Early(name, index) => ty::Region::new_early_param(
|
||||
self.tcx,
|
||||
ty::EarlyParamRegion { name, index },
|
||||
),
|
||||
ParamKind::Free(def_id, name) => ty::Region::new_late_param(
|
||||
self.tcx,
|
||||
self.parent_def_id.to_def_id(),
|
||||
ty::BoundRegionKind::BrNamed(def_id, name),
|
||||
),
|
||||
// Totally ignore late bound args from binders.
|
||||
ParamKind::Late => return true,
|
||||
};
|
||||
// Does this region outlive any captured region?
|
||||
!captured_regions.iter().any(|r| {
|
||||
self.outlives_env
|
||||
.free_region_map()
|
||||
.sub_free_regions(self.tcx, *r, uncaptured)
|
||||
})
|
||||
});
|
||||
|
||||
// If we have uncaptured args, and if the opaque doesn't already have
|
||||
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
|
||||
if !uncaptured_args.is_empty() {
|
||||
let suggestion = if let Ok(snippet) =
|
||||
self.tcx.sess.source_map().span_to_snippet(opaque_span)
|
||||
&& snippet.starts_with("impl ")
|
||||
{
|
||||
let (lifetimes, others): (Vec<_>, Vec<_>) =
|
||||
captured.into_iter().partition(|def_id| {
|
||||
self.tcx.def_kind(*def_id) == DefKind::LifetimeParam
|
||||
});
|
||||
// Take all lifetime params first, then all others (ty/ct).
|
||||
let generics: Vec<_> = lifetimes
|
||||
.into_iter()
|
||||
.chain(others)
|
||||
.map(|def_id| self.tcx.item_name(def_id).to_string())
|
||||
.collect();
|
||||
// Make sure that we're not trying to name any APITs
|
||||
if generics.iter().all(|name| !name.starts_with("impl ")) {
|
||||
Some((
|
||||
format!(" + use<{}>", generics.join(", ")),
|
||||
opaque_span.shrink_to_hi(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
};
|
||||
|
||||
self.tcx.emit_node_span_lint(
|
||||
IMPL_TRAIT_OVERCAPTURES,
|
||||
self.tcx.local_def_id_to_hir_id(opaque_def_id),
|
||||
opaque_span,
|
||||
ImplTraitOvercapturesLint {
|
||||
self_ty: t,
|
||||
num_captured: uncaptured_spans.len(),
|
||||
uncaptured_spans,
|
||||
suggestion,
|
||||
},
|
||||
);
|
||||
let uncaptured_spans: Vec<_> = uncaptured_args
|
||||
.into_iter()
|
||||
.map(|(def_id, _)| self.tcx.def_span(def_id))
|
||||
.collect();
|
||||
|
||||
self.tcx.emit_node_span_lint(
|
||||
IMPL_TRAIT_OVERCAPTURES,
|
||||
self.tcx.local_def_id_to_hir_id(opaque_def_id),
|
||||
opaque_span,
|
||||
ImplTraitOvercapturesLint {
|
||||
self_ty: t,
|
||||
num_captured: uncaptured_spans.len(),
|
||||
uncaptured_spans,
|
||||
suggestion,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, if we are edition 2024, have `use<>` syntax, and
|
||||
// have no uncaptured args, then we should warn to the user that
|
||||
// it's redundant to capture all args explicitly.
|
||||
else if new_capture_rules
|
||||
if new_capture_rules
|
||||
&& let Some((captured_args, capturing_span)) =
|
||||
opaque.bounds.iter().find_map(|bound| match *bound {
|
||||
hir::GenericBound::Use(a, s) => Some((a, s)),
|
||||
|
@ -327,7 +419,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
|||
if self
|
||||
.in_scope_parameters
|
||||
.iter()
|
||||
.all(|def_id| explicitly_captured.contains(def_id))
|
||||
.all(|(def_id, _)| explicitly_captured.contains(def_id))
|
||||
{
|
||||
self.tcx.emit_node_span_lint(
|
||||
IMPL_TRAIT_REDUNDANT_CAPTURES,
|
||||
|
@ -396,7 +488,11 @@ fn extract_def_id_from_arg<'tcx>(
|
|||
ty::ReBound(
|
||||
_,
|
||||
ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. },
|
||||
) => def_id,
|
||||
)
|
||||
| ty::ReLateParam(ty::LateParamRegion {
|
||||
scope: _,
|
||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, ..),
|
||||
}) => def_id,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
|
@ -413,3 +509,106 @@ fn extract_def_id_from_arg<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the variances of regions that appear in the type, but considering
|
||||
/// late-bound regions too, which don't have their variance computed usually.
|
||||
///
|
||||
/// Like generalization, this is a unary operation implemented on top of the binary
|
||||
/// relation infrastructure, mostly because it's much easier to have the relation
|
||||
/// track the variance for you, rather than having to do it yourself.
|
||||
struct FunctionalVariances<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
variances: FxHashMap<DefId, ty::Variance>,
|
||||
ambient_variance: ty::Variance,
|
||||
generics: &'tcx ty::Generics,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for FunctionalVariances<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn relate_with_variance<T: ty::relate::Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
variance: rustc_type_ir::Variance,
|
||||
_: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
|
||||
a: T,
|
||||
b: T,
|
||||
) -> RelateResult<'tcx, T> {
|
||||
let old_variance = self.ambient_variance;
|
||||
self.ambient_variance = self.ambient_variance.xform(variance);
|
||||
self.relate(a, b).unwrap();
|
||||
self.ambient_variance = old_variance;
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
|
||||
structurally_relate_tys(self, a, b).unwrap();
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn regions(
|
||||
&mut self,
|
||||
a: ty::Region<'tcx>,
|
||||
_: ty::Region<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Region<'tcx>> {
|
||||
let def_id = match *a {
|
||||
ty::ReEarlyParam(ebr) => self.generics.region_param(ebr, self.tcx).def_id,
|
||||
ty::ReBound(
|
||||
_,
|
||||
ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. },
|
||||
)
|
||||
| ty::ReLateParam(ty::LateParamRegion {
|
||||
scope: _,
|
||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, ..),
|
||||
}) => def_id,
|
||||
_ => {
|
||||
return Ok(a);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(variance) = self.variances.get_mut(&def_id) {
|
||||
*variance = unify(*variance, self.ambient_variance);
|
||||
} else {
|
||||
self.variances.insert(def_id, self.ambient_variance);
|
||||
}
|
||||
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn consts(
|
||||
&mut self,
|
||||
a: ty::Const<'tcx>,
|
||||
b: ty::Const<'tcx>,
|
||||
) -> RelateResult<'tcx, ty::Const<'tcx>> {
|
||||
structurally_relate_consts(self, a, b).unwrap();
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
fn binders<T>(
|
||||
&mut self,
|
||||
a: ty::Binder<'tcx, T>,
|
||||
b: ty::Binder<'tcx, T>,
|
||||
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
|
||||
where
|
||||
T: Relate<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.relate(a.skip_binder(), b.skip_binder()).unwrap();
|
||||
Ok(a)
|
||||
}
|
||||
}
|
||||
|
||||
/// What is the variance that satisfies the two variances?
|
||||
fn unify(a: ty::Variance, b: ty::Variance) -> ty::Variance {
|
||||
match (a, b) {
|
||||
// Bivariance is lattice bottom.
|
||||
(ty::Bivariant, other) | (other, ty::Bivariant) => other,
|
||||
// Invariant is lattice top.
|
||||
(ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
|
||||
// If type is required to be covariant and contravariant, then it's invariant.
|
||||
(ty::Contravariant, ty::Covariant) | (ty::Covariant, ty::Contravariant) => ty::Invariant,
|
||||
// Otherwise, co + co = co, contra + contra = contra.
|
||||
(ty::Contravariant, ty::Contravariant) => ty::Contravariant,
|
||||
(ty::Covariant, ty::Covariant) => ty::Covariant,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ use tracing::debug;
|
|||
use crate::lints::{
|
||||
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
|
||||
NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag,
|
||||
TykindKind, UntranslatableDiag,
|
||||
TykindKind, TypeIrInherentUsage, UntranslatableDiag,
|
||||
};
|
||||
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
|
||||
|
@ -277,13 +277,39 @@ declare_tool_lint! {
|
|||
report_in_external_macro: true
|
||||
}
|
||||
|
||||
declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT]);
|
||||
declare_tool_lint! {
|
||||
/// The `usage_of_type_ir_inherent` lint detects usage `rustc_type_ir::inherent`.
|
||||
///
|
||||
/// This module should only be used within the trait solver.
|
||||
pub rustc::USAGE_OF_TYPE_IR_INHERENT,
|
||||
Allow,
|
||||
"usage `rustc_type_ir::inherent` outside of trait system",
|
||||
report_in_external_macro: true
|
||||
}
|
||||
|
||||
declare_lint_pass!(TypeIr => [NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for TypeIr {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return };
|
||||
|
||||
let is_mod_inherent = |def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id);
|
||||
|
||||
// Path segments except for the final.
|
||||
if let Some(seg) =
|
||||
path.segments.iter().find(|seg| seg.res.opt_def_id().is_some_and(is_mod_inherent))
|
||||
{
|
||||
cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage);
|
||||
}
|
||||
// Final path resolutions, like `use rustc_type_ir::inherent`
|
||||
else if path.res.iter().any(|res| res.opt_def_id().is_some_and(is_mod_inherent)) {
|
||||
cx.emit_span_lint(
|
||||
USAGE_OF_TYPE_IR_INHERENT,
|
||||
path.segments.last().unwrap().ident.span,
|
||||
TypeIrInherentUsage,
|
||||
);
|
||||
}
|
||||
|
||||
let (lo, hi, snippet) = match path.segments {
|
||||
[.., penultimate, segment]
|
||||
if penultimate.res.opt_def_id().is_some_and(is_mod_inherent) =>
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(array_windows)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(extract_if)]
|
||||
|
|
|
@ -918,6 +918,11 @@ pub(crate) struct TyQualified {
|
|||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_type_ir_inherent_usage)]
|
||||
#[note]
|
||||
pub(crate) struct TypeIrInherentUsage;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_non_glob_import_type_ir_inherent)]
|
||||
pub(crate) struct NonGlobImportTypeIrInherent {
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
|||
// > same expression-containing item.
|
||||
//
|
||||
// To achieve this we get try to get the paths of the _Trait_ and
|
||||
// _Type_, and we look inside thoses paths to try a find in one
|
||||
// _Type_, and we look inside those paths to try a find in one
|
||||
// of them a type whose parent is the same as the impl definition.
|
||||
//
|
||||
// If that's the case this means that this impl block declaration
|
||||
|
|
|
@ -734,7 +734,7 @@ trait UnusedDelimLint {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Check if we need parens for `match &( Struct { feild: }) {}`.
|
||||
// Check if we need parens for `match &( Struct { field: }) {}`.
|
||||
{
|
||||
let mut innermost = inner;
|
||||
loop {
|
||||
|
|
|
@ -3706,7 +3706,7 @@ declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
|
|||
|
||||
declare_lint! {
|
||||
/// The `missing_abi` lint detects cases where the ABI is omitted from
|
||||
/// extern declarations.
|
||||
/// `extern` declarations.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
|
@ -3720,10 +3720,12 @@ declare_lint! {
|
|||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Historically, Rust implicitly selected C as the ABI for extern
|
||||
/// declarations. We expect to add new ABIs, like `C-unwind`, in the future,
|
||||
/// though this has not yet happened, and especially with their addition
|
||||
/// seeing the ABI easily will make code review easier.
|
||||
/// For historic reasons, Rust implicitly selects `C` as the default ABI for
|
||||
/// `extern` declarations. [Other ABIs] like `C-unwind` and `system` have
|
||||
/// been added since then, and especially with their addition seeing the ABI
|
||||
/// easily makes code review easier.
|
||||
///
|
||||
/// [Other ABIs]: https://doc.rust-lang.org/reference/items/external-blocks.html#abi
|
||||
pub MISSING_ABI,
|
||||
Allow,
|
||||
"No declared ABI for extern declaration"
|
||||
|
|
|
@ -71,8 +71,8 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>> ProcessQueryValue<'
|
|||
for Option<DecodeIterator<'a, 'tcx, T>>
|
||||
{
|
||||
#[inline(always)]
|
||||
fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> &'tcx [T] {
|
||||
if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { &[] }
|
||||
fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx [T] {
|
||||
if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { err() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,12 +84,12 @@ impl<'a, 'tcx, T: Copy + Decodable<DecodeContext<'a, 'tcx>>>
|
|||
fn process_decoded(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_err: impl Fn() -> !,
|
||||
err: impl Fn() -> !,
|
||||
) -> ty::EarlyBinder<'tcx, &'tcx [T]> {
|
||||
ty::EarlyBinder::bind(if let Some(iter) = self {
|
||||
tcx.arena.alloc_from_iter(iter)
|
||||
} else {
|
||||
&[]
|
||||
err()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -247,8 +247,8 @@ provide! { tcx, def_id, other, cdata,
|
|||
explicit_predicates_of => { table }
|
||||
generics_of => { table }
|
||||
inferred_outlives_of => { table_defaulted_array }
|
||||
explicit_super_predicates_of => { table }
|
||||
explicit_implied_predicates_of => { table }
|
||||
explicit_super_predicates_of => { table_defaulted_array }
|
||||
explicit_implied_predicates_of => { table_defaulted_array }
|
||||
type_of => { table }
|
||||
type_alias_is_lazy => { table_direct }
|
||||
variances_of => { table }
|
||||
|
@ -300,7 +300,20 @@ provide! { tcx, def_id, other, cdata,
|
|||
.unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer")))
|
||||
}
|
||||
trait_def => { table }
|
||||
deduced_param_attrs => { table }
|
||||
deduced_param_attrs => {
|
||||
// FIXME: `deduced_param_attrs` has some sketchy encoding settings,
|
||||
// where we don't encode unless we're optimizing, doing codegen,
|
||||
// and not incremental (see `encoder.rs`). I don't think this is right!
|
||||
cdata
|
||||
.root
|
||||
.tables
|
||||
.deduced_param_attrs
|
||||
.get(cdata, def_id.index)
|
||||
.map(|lazy| {
|
||||
&*tcx.arena.alloc_from_iter(lazy.decode((cdata, tcx)))
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
is_type_alias_impl_trait => {
|
||||
debug_assert_eq!(tcx.def_kind(def_id), DefKind::OpaqueTy);
|
||||
cdata.root.tables.is_type_alias_impl_trait.get(cdata, def_id.index)
|
||||
|
|
|
@ -1443,9 +1443,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
if let DefKind::Trait = def_kind {
|
||||
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
|
||||
record_array!(self.tables.explicit_super_predicates_of[def_id] <-
|
||||
record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
|
||||
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
|
||||
record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
|
||||
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
|
||||
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
|
||||
|
||||
let module_children = self.tcx.module_children_local(local_id);
|
||||
|
@ -1454,9 +1454,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
if let DefKind::TraitAlias = def_kind {
|
||||
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
|
||||
record_array!(self.tables.explicit_super_predicates_of[def_id] <-
|
||||
record_defaulted_array!(self.tables.explicit_super_predicates_of[def_id] <-
|
||||
self.tcx.explicit_super_predicates_of(def_id).skip_binder());
|
||||
record_array!(self.tables.explicit_implied_predicates_of[def_id] <-
|
||||
record_defaulted_array!(self.tables.explicit_implied_predicates_of[def_id] <-
|
||||
self.tcx.explicit_implied_predicates_of(def_id).skip_binder());
|
||||
}
|
||||
if let DefKind::Trait | DefKind::Impl { .. } = def_kind {
|
||||
|
|
|
@ -390,6 +390,8 @@ define_tables! {
|
|||
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
|
||||
associated_type_for_effects: Table<DefIndex, Option<LazyValue<DefId>>>,
|
||||
|
@ -419,10 +421,6 @@ define_tables! {
|
|||
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
|
||||
explicit_predicates_of: Table<DefIndex, LazyValue<ty::GenericPredicates<'static>>>,
|
||||
generics_of: Table<DefIndex, LazyValue<ty::Generics>>,
|
||||
explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
// As an optimization, we only store this for trait aliases,
|
||||
// since it's identical to explicit_super_predicates_of for traits.
|
||||
explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
type_of: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, Ty<'static>>>>,
|
||||
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
|
||||
fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,
|
||||
|
|
|
@ -40,5 +40,6 @@ tracing = "0.1"
|
|||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
rustc_randomized_layouts = []
|
||||
rustc_use_parallel_compiler = ["dep:rustc-rayon-core"]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -240,7 +240,7 @@ impl<'tcx> Const<'tcx> {
|
|||
match self {
|
||||
Const::Ty(ty, ct) => {
|
||||
match ct.kind() {
|
||||
// Dont use the outter ty as on invalid code we can wind up with them not being the same.
|
||||
// Dont use the outer ty as on invalid code we can wind up with them not being the same.
|
||||
// this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
|
||||
// was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
|
|
|
@ -91,9 +91,9 @@ pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled
|
|||
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
|
||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
|
||||
/// because the value containts something of type `ty` that is not valtree-compatible.
|
||||
/// because the value contains something of type `ty` that is not valtree-compatible.
|
||||
/// The caller can then show an appropriate error; the query does not have the
|
||||
/// necssary context to give good user-facing errors for this case.
|
||||
/// necessary context to give good user-facing errors for this case.
|
||||
pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
|
@ -231,7 +231,7 @@ pub enum CheckInAllocMsg {
|
|||
pub enum CheckAlignMsg {
|
||||
/// The accessed pointer did not have proper alignment.
|
||||
AccessedPtr,
|
||||
/// The access ocurred with a place that was based on a misaligned pointer.
|
||||
/// The access occurred with a place that was based on a misaligned pointer.
|
||||
BasedOn,
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::{iter, mem};
|
||||
|
@ -26,7 +24,6 @@ use rustc_index::bit_set::BitSet;
|
|||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
@ -106,65 +103,6 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
|
||||
RefCell::new(FxHashMap::default())
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts a MIR pass name into a snake case form to match the profiling naming style.
|
||||
fn to_profiler_name(type_name: &'static str) -> &'static str {
|
||||
PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
|
||||
Entry::Occupied(e) => *e.get(),
|
||||
Entry::Vacant(e) => {
|
||||
let snake_case: String = type_name
|
||||
.chars()
|
||||
.flat_map(|c| {
|
||||
if c.is_ascii_uppercase() {
|
||||
vec!['_', c.to_ascii_lowercase()]
|
||||
} else if c == '-' {
|
||||
vec!['_']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let result = &*String::leak(format!("mir_pass{}", snake_case));
|
||||
e.insert(result);
|
||||
result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create a pass; the
|
||||
/// pass will be named after the type, and it will consist of a main
|
||||
/// loop that goes over each available MIR and applies `run_pass`.
|
||||
pub trait MirPass<'tcx> {
|
||||
fn name(&self) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// See copypaste in `MirLint`
|
||||
const {
|
||||
let name = std::any::type_name::<Self>();
|
||||
crate::util::common::c_name(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn profiler_name(&self) -> &'static str {
|
||||
to_profiler_name(self.name())
|
||||
}
|
||||
|
||||
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
|
||||
fn is_enabled(&self, _sess: &Session) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
|
||||
|
||||
fn is_mir_dump_enabled(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl MirPhase {
|
||||
/// Gets the index of the current MirPhase within the set of all `MirPhase`s.
|
||||
///
|
||||
|
|
|
@ -612,7 +612,9 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io:
|
|||
let def_id = body.source.def_id();
|
||||
let kind = tcx.def_kind(def_id);
|
||||
let is_function = match kind {
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::SyntheticCoroutineBody => {
|
||||
true
|
||||
}
|
||||
_ => tcx.is_closure_like(def_id),
|
||||
};
|
||||
match (kind, body.source.promoted) {
|
||||
|
|
|
@ -327,7 +327,7 @@ rustc_queries! {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the list of bounds that are required to be satsified
|
||||
/// Returns the list of bounds that are required to be satisfied
|
||||
/// by a implementation or definition. For associated types, these
|
||||
/// must be satisfied for an implementation to be well-formed,
|
||||
/// and for opaque types, these are required to be satisfied by
|
||||
|
|
|
@ -337,6 +337,7 @@ macro_rules! define_callbacks {
|
|||
// Ensure that values grow no larger than 64 bytes by accident.
|
||||
// Increase this limit if necessary, but do try to keep the size low if possible
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
#[cfg(not(feature = "rustc_randomized_layouts"))]
|
||||
const _: () = {
|
||||
if mem::size_of::<Value<'static>>() > 64 {
|
||||
panic!("{}", concat!(
|
||||
|
|
|
@ -1475,7 +1475,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// provides a `TyCtxt`.
|
||||
///
|
||||
/// By only providing the `TyCtxt` inside of the closure we enforce that the type
|
||||
/// context and any interned alue (types, args, etc.) can only be used while `ty::tls`
|
||||
/// context and any interned value (types, args, etc.) can only be used while `ty::tls`
|
||||
/// has a valid reference to the context, to allow formatting values that need it.
|
||||
pub fn create_global_ctxt(
|
||||
s: &'tcx Session,
|
||||
|
|
|
@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
|
|||
adt: ty::AdtDef<'_>,
|
||||
) -> InhabitedPredicate<'tcx> {
|
||||
debug_assert!(!adt.is_union());
|
||||
if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
|
||||
// Non-exhaustive variants from other crates are always considered inhabited.
|
||||
return InhabitedPredicate::True;
|
||||
}
|
||||
InhabitedPredicate::all(
|
||||
tcx,
|
||||
self.fields.iter().map(|field| {
|
||||
|
|
|
@ -38,7 +38,7 @@ pub struct Instance<'tcx> {
|
|||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
/// Describes why a `ReifyShim` was created. This is needed to distingish a ReifyShim created to
|
||||
/// Describes why a `ReifyShim` was created. This is needed to distinguish a ReifyShim created to
|
||||
/// adjust for things like `#[track_caller]` in a vtable from a `ReifyShim` created to produce a
|
||||
/// function pointer from a vtable entry.
|
||||
/// Currently, this is only used when KCFI is enabled, as only KCFI needs to treat those two
|
||||
|
|
|
@ -35,6 +35,7 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
|||
use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{
|
||||
extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
|
||||
|
@ -1570,8 +1571,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
flags.insert(ReprFlags::RANDOMIZE_LAYOUT);
|
||||
}
|
||||
|
||||
// box is special, on the one hand the compiler assumes an ordered layout, with the pointer
|
||||
// always at offset zero. On the other hand we want scalar abi optimizations.
|
||||
let is_box = self.is_lang_item(did.to_def_id(), LangItem::OwnedBox);
|
||||
|
||||
// This is here instead of layout because the choice must make it into metadata.
|
||||
if !self.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did))) {
|
||||
if is_box
|
||||
|| !self
|
||||
.consider_optimizing(|| format!("Reorder fields of {:?}", self.def_path_str(did)))
|
||||
{
|
||||
flags.insert(ReprFlags::IS_LINEAR);
|
||||
}
|
||||
|
||||
|
@ -1819,7 +1827,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
self.get_attrs(did, attr).next().is_some()
|
||||
}
|
||||
|
||||
/// Determines whether an item is annotated with a multi-segement attribute
|
||||
/// Determines whether an item is annotated with a multi-segment attribute
|
||||
pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
|
||||
self.get_attrs_by_path(did.into(), attrs).next().is_some()
|
||||
}
|
||||
|
|
|
@ -1930,7 +1930,7 @@ impl<'tcx> Ty<'tcx> {
|
|||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, sice even if their arguments or
|
||||
/// things like ADTs and trait objects, since even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
pub fn is_known_rigid(self) -> bool {
|
||||
|
|
|
@ -20,19 +20,3 @@ pub fn to_readable_str(mut val: usize) -> String {
|
|||
|
||||
groups.join("_")
|
||||
}
|
||||
|
||||
// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
|
||||
pub const fn c_name(name: &'static str) -> &'static str {
|
||||
// FIXME Simplify the implementation once more `str` methods get const-stable.
|
||||
// and inline into call site
|
||||
let bytes = name.as_bytes();
|
||||
let mut i = bytes.len();
|
||||
while i > 0 && bytes[i - 1] != b':' {
|
||||
i = i - 1;
|
||||
}
|
||||
let (_, bytes) = bytes.split_at(i);
|
||||
match std::str::from_utf8(bytes) {
|
||||
Ok(name) => name,
|
||||
Err(_) => name,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::MetaItem;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_middle::mir::{self, Body, Local, Location, MirPass};
|
||||
use rustc_middle::mir::{self, Body, Local, Location};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
@ -18,8 +18,6 @@ use crate::impls::{
|
|||
use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
|
||||
use crate::{Analysis, JoinSemiLattice, ResultsCursor};
|
||||
|
||||
pub struct SanityCheck;
|
||||
|
||||
fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
|
||||
for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
|
||||
let items = attr.meta_item_list();
|
||||
|
@ -33,53 +31,50 @@ fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<Me
|
|||
None
|
||||
}
|
||||
|
||||
// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
|
||||
impl<'tcx> MirPass<'tcx> for SanityCheck {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
if !tcx.has_attr(def_id, sym::rustc_mir) {
|
||||
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
return;
|
||||
} else {
|
||||
debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
}
|
||||
pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
if !tcx.has_attr(def_id, sym::rustc_mir) {
|
||||
debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
return;
|
||||
} else {
|
||||
debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
|
||||
}
|
||||
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
||||
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
|
||||
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
|
||||
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||
let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
|
||||
let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
|
||||
.into_engine(tcx, body)
|
||||
.iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
||||
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
|
||||
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
|
||||
|
||||
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||
}
|
||||
sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
|
||||
}
|
||||
|
||||
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
||||
tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
|
||||
}
|
||||
if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
|
||||
tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use rustc_target::spec::PanicStrategy;
|
|||
#[derive(PartialEq)]
|
||||
pub struct AbortUnwindingCalls;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let def_id = body.source.def_id();
|
||||
let kind = tcx.def_kind(def_id);
|
||||
|
|
|
@ -30,7 +30,7 @@ pub use self::AddCallGuards::*;
|
|||
*
|
||||
*/
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddCallGuards {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
self.add_call_guards(body);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ use crate::util;
|
|||
/// blowup.
|
||||
pub struct AddMovesForPackedDrops;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
|
||||
add_moves_for_packed_drops(tcx, body);
|
||||
|
@ -86,7 +86,7 @@ fn add_move_for_packed_drop<'tcx>(
|
|||
|
||||
let source_info = terminator.source_info;
|
||||
let ty = place.ty(body, tcx).ty;
|
||||
let temp = patch.new_temp(ty, terminator.source_info.span);
|
||||
let temp = patch.new_temp(ty, source_info.span);
|
||||
|
||||
let storage_dead_block = patch.new_block(BasicBlockData {
|
||||
statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }],
|
||||
|
|
|
@ -48,7 +48,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for AddRetag {
|
||||
impl<'tcx> crate::MirPass<'tcx> for AddRetag {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.opts.unstable_opts.mir_emit_retag
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
checker.patcher.apply(body);
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for Subtyper {
|
||||
impl<'tcx> crate::MirPass<'tcx> for Subtyper {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
subtype_finder(tcx, body);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use tracing::{debug, trace};
|
|||
|
||||
pub struct CheckAlignment;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CheckAlignment {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
|
||||
fn is_enabled(&self, sess: &Session) -> bool {
|
||||
// FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
|
||||
if sess.target.llvm_target == "i686-pc-windows-msvc" {
|
||||
|
|
|
@ -6,11 +6,11 @@ use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
|||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::{errors, MirLint};
|
||||
use crate::errors;
|
||||
|
||||
pub struct CheckConstItemMutation;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
|
||||
impl<'tcx> crate::MirLint<'tcx> for CheckConstItemMutation {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let mut checker = ConstMutationChecker { body, tcx, target_local: None };
|
||||
checker.visit_body(body);
|
||||
|
|
|
@ -3,11 +3,11 @@ use rustc_middle::mir::*;
|
|||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
||||
use crate::{errors, util, MirLint};
|
||||
use crate::{errors, util};
|
||||
|
||||
pub struct CheckPackedRef;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for CheckPackedRef {
|
||||
impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
|
||||
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
let param_env = tcx.param_env(body.source.def_id());
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
|
@ -37,24 +37,17 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
let def_id = self.body.source.instance.def_id();
|
||||
if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
|
||||
&& self.tcx.is_builtin_derived(impl_def_id)
|
||||
{
|
||||
// If we ever reach here it means that the generated derive
|
||||
// code is somehow doing an unaligned reference, which it
|
||||
// shouldn't do.
|
||||
span_bug!(
|
||||
self.source_info.span,
|
||||
"builtin derive created an unaligned reference"
|
||||
);
|
||||
} else {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
|
||||
}
|
||||
if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
let def_id = self.body.source.instance.def_id();
|
||||
if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
|
||||
&& self.tcx.is_builtin_derived(impl_def_id)
|
||||
{
|
||||
// If we ever reach here it means that the generated derive
|
||||
// code is somehow doing an unaligned reference, which it
|
||||
// shouldn't do.
|
||||
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
|
||||
} else {
|
||||
self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,9 @@ use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, Termi
|
|||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct CleanupPostBorrowck;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
for basic_block in body.basic_blocks.as_mut() {
|
||||
for statement in basic_block.statements.iter_mut() {
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::ssa::SsaLocals;
|
|||
/// We want to replace all those locals by `_a`, either copied or moved.
|
||||
pub struct CopyProp;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CopyProp {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CopyProp {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 1
|
||||
}
|
||||
|
|
|
@ -63,7 +63,9 @@ use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet};
|
|||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, InstanceKind, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
|
||||
|
@ -113,11 +115,18 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct DerefArgVisitor<'tcx> {
|
||||
struct SelfArgVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
new_base: Place<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
|
||||
impl<'tcx> SelfArgVisitor<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>, elem: ProjectionElem<Local, Ty<'tcx>>) -> Self {
|
||||
Self { tcx, new_base: Place { local: SELF_ARG, projection: tcx.mk_place_elems(&[elem]) } }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for SelfArgVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
@ -128,53 +137,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
|
|||
|
||||
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
if place.local == SELF_ARG {
|
||||
replace_base(
|
||||
place,
|
||||
Place {
|
||||
local: SELF_ARG,
|
||||
projection: self.tcx().mk_place_elems(&[ProjectionElem::Deref]),
|
||||
},
|
||||
self.tcx,
|
||||
);
|
||||
} else {
|
||||
self.visit_local(&mut place.local, context, location);
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
if let PlaceElem::Index(local) = elem {
|
||||
assert_ne!(local, SELF_ARG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PinArgVisitor<'tcx> {
|
||||
ref_coroutine_ty: Ty<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
|
||||
assert_ne!(*local, SELF_ARG);
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
if place.local == SELF_ARG {
|
||||
replace_base(
|
||||
place,
|
||||
Place {
|
||||
local: SELF_ARG,
|
||||
projection: self.tcx().mk_place_elems(&[ProjectionElem::Field(
|
||||
FieldIdx::ZERO,
|
||||
self.ref_coroutine_ty,
|
||||
)]),
|
||||
},
|
||||
self.tcx,
|
||||
);
|
||||
replace_base(place, self.new_base, self.tcx);
|
||||
} else {
|
||||
self.visit_local(&mut place.local, context, location);
|
||||
|
||||
|
@ -198,15 +161,6 @@ fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtx
|
|||
|
||||
const SELF_ARG: Local = Local::from_u32(1);
|
||||
|
||||
/// Coroutine has not been resumed yet.
|
||||
const UNRESUMED: usize = CoroutineArgs::UNRESUMED;
|
||||
/// Coroutine has returned / is completed.
|
||||
const RETURNED: usize = CoroutineArgs::RETURNED;
|
||||
/// Coroutine has panicked and is poisoned.
|
||||
const POISONED: usize = CoroutineArgs::POISONED;
|
||||
/// Number of reserved variants of coroutine state.
|
||||
const RESERVED_VARIANTS: usize = CoroutineArgs::RESERVED_VARIANTS;
|
||||
|
||||
/// A `yield` point in the coroutine.
|
||||
struct SuspensionPoint<'tcx> {
|
||||
/// State discriminant used when suspending or resuming at this point.
|
||||
|
@ -261,14 +215,10 @@ impl<'tcx> TransformVisitor<'tcx> {
|
|||
// `gen` continues return `None`
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
|
||||
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
option_def_id,
|
||||
VariantIdx::ZERO,
|
||||
self.tcx.mk_args(&[self.old_yield_ty.into()]),
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
make_aggregate_adt(
|
||||
option_def_id,
|
||||
VariantIdx::ZERO,
|
||||
self.tcx.mk_args(&[self.old_yield_ty.into()]),
|
||||
IndexVec::new(),
|
||||
)
|
||||
}
|
||||
|
@ -317,64 +267,28 @@ impl<'tcx> TransformVisitor<'tcx> {
|
|||
is_return: bool,
|
||||
statements: &mut Vec<Statement<'tcx>>,
|
||||
) {
|
||||
const ZERO: VariantIdx = VariantIdx::ZERO;
|
||||
const ONE: VariantIdx = VariantIdx::from_usize(1);
|
||||
let rvalue = match self.coroutine_kind {
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
|
||||
let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None);
|
||||
let args = self.tcx.mk_args(&[self.old_ret_ty.into()]);
|
||||
if is_return {
|
||||
// Poll::Ready(val)
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
poll_def_id,
|
||||
VariantIdx::ZERO,
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::from_raw(vec![val]),
|
||||
)
|
||||
let (variant_idx, operands) = if is_return {
|
||||
(ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val)
|
||||
} else {
|
||||
// Poll::Pending
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
poll_def_id,
|
||||
VariantIdx::from_usize(1),
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::new(),
|
||||
)
|
||||
}
|
||||
(ONE, IndexVec::new()) // Poll::Pending
|
||||
};
|
||||
make_aggregate_adt(poll_def_id, variant_idx, args, operands)
|
||||
}
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {
|
||||
let option_def_id = self.tcx.require_lang_item(LangItem::Option, None);
|
||||
let args = self.tcx.mk_args(&[self.old_yield_ty.into()]);
|
||||
if is_return {
|
||||
// None
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
option_def_id,
|
||||
VariantIdx::ZERO,
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::new(),
|
||||
)
|
||||
let (variant_idx, operands) = if is_return {
|
||||
(ZERO, IndexVec::new()) // None
|
||||
} else {
|
||||
// Some(val)
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
option_def_id,
|
||||
VariantIdx::from_usize(1),
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::from_raw(vec![val]),
|
||||
)
|
||||
}
|
||||
(ONE, IndexVec::from_raw(vec![val])) // Some(val)
|
||||
};
|
||||
make_aggregate_adt(option_def_id, variant_idx, args, operands)
|
||||
}
|
||||
CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => {
|
||||
if is_return {
|
||||
|
@ -400,31 +314,17 @@ impl<'tcx> TransformVisitor<'tcx> {
|
|||
let coroutine_state_def_id =
|
||||
self.tcx.require_lang_item(LangItem::CoroutineState, None);
|
||||
let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]);
|
||||
if is_return {
|
||||
// CoroutineState::Complete(val)
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
coroutine_state_def_id,
|
||||
VariantIdx::from_usize(1),
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::from_raw(vec![val]),
|
||||
)
|
||||
let variant_idx = if is_return {
|
||||
ONE // CoroutineState::Complete(val)
|
||||
} else {
|
||||
// CoroutineState::Yielded(val)
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
coroutine_state_def_id,
|
||||
VariantIdx::ZERO,
|
||||
args,
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
IndexVec::from_raw(vec![val]),
|
||||
)
|
||||
}
|
||||
ZERO // CoroutineState::Yielded(val)
|
||||
};
|
||||
make_aggregate_adt(
|
||||
coroutine_state_def_id,
|
||||
variant_idx,
|
||||
args,
|
||||
IndexVec::from_raw(vec![val]),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -517,7 +417,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
self.make_state(v, source_info, is_return, &mut data.statements);
|
||||
let state = if let Some((resume, mut resume_arg)) = resume {
|
||||
// Yield
|
||||
let state = RESERVED_VARIANTS + self.suspension_points.len();
|
||||
let state = CoroutineArgs::RESERVED_VARIANTS + self.suspension_points.len();
|
||||
|
||||
// The resume arg target location might itself be remapped if its base local is
|
||||
// live across a yield.
|
||||
|
@ -550,7 +450,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
VariantIdx::new(state)
|
||||
} else {
|
||||
// Return
|
||||
VariantIdx::new(RETURNED) // state for returned
|
||||
VariantIdx::new(CoroutineArgs::RETURNED) // state for returned
|
||||
};
|
||||
data.statements.push(self.set_discr(state, source_info));
|
||||
data.terminator_mut().kind = TerminatorKind::Return;
|
||||
|
@ -560,6 +460,15 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_aggregate_adt<'tcx>(
|
||||
def_id: DefId,
|
||||
variant_idx: VariantIdx,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
operands: IndexVec<FieldIdx, Operand<'tcx>>,
|
||||
) -> Rvalue<'tcx> {
|
||||
Rvalue::Aggregate(Box::new(AggregateKind::Adt(def_id, variant_idx, args, None, None)), operands)
|
||||
}
|
||||
|
||||
fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let coroutine_ty = body.local_decls.raw[1].ty;
|
||||
|
||||
|
@ -569,7 +478,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo
|
|||
body.local_decls.raw[1].ty = ref_coroutine_ty;
|
||||
|
||||
// Add a deref to accesses of the coroutine state
|
||||
DerefArgVisitor { tcx }.visit_body(body);
|
||||
SelfArgVisitor::new(tcx, ProjectionElem::Deref).visit_body(body);
|
||||
}
|
||||
|
||||
fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
|
@ -584,7 +493,8 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
|
|||
body.local_decls.raw[1].ty = pin_ref_coroutine_ty;
|
||||
|
||||
// Add the Pin field access to accesses of the coroutine state
|
||||
PinArgVisitor { ref_coroutine_ty, tcx }.visit_body(body);
|
||||
SelfArgVisitor::new(tcx, ProjectionElem::Field(FieldIdx::ZERO, ref_coroutine_ty))
|
||||
.visit_body(body);
|
||||
}
|
||||
|
||||
/// Allocates a new local and replaces all references of `local` with it. Returns the new local.
|
||||
|
@ -651,8 +561,6 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
let local = eliminate_get_context_call(&mut body[bb]);
|
||||
replace_resume_ty_local(tcx, body, local, context_mut_ref);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
TerminatorKind::Yield { resume_arg, .. } => {
|
||||
|
@ -665,24 +573,23 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
|
||||
fn eliminate_get_context_call<'tcx>(bb_data: &mut BasicBlockData<'tcx>) -> Local {
|
||||
let terminator = bb_data.terminator.take().unwrap();
|
||||
if let TerminatorKind::Call { args, destination, target, .. } = terminator.kind {
|
||||
let [arg] = *Box::try_from(args).unwrap();
|
||||
let local = arg.node.place().unwrap().local;
|
||||
|
||||
let arg = Rvalue::Use(arg.node);
|
||||
let assign = Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::Assign(Box::new((destination, arg))),
|
||||
};
|
||||
bb_data.statements.push(assign);
|
||||
bb_data.terminator = Some(Terminator {
|
||||
source_info: terminator.source_info,
|
||||
kind: TerminatorKind::Goto { target: target.unwrap() },
|
||||
});
|
||||
local
|
||||
} else {
|
||||
let TerminatorKind::Call { args, destination, target, .. } = terminator.kind else {
|
||||
bug!();
|
||||
}
|
||||
};
|
||||
let [arg] = *Box::try_from(args).unwrap();
|
||||
let local = arg.node.place().unwrap().local;
|
||||
|
||||
let arg = Rvalue::Use(arg.node);
|
||||
let assign = Statement {
|
||||
source_info: terminator.source_info,
|
||||
kind: StatementKind::Assign(Box::new((destination, arg))),
|
||||
};
|
||||
bb_data.statements.push(assign);
|
||||
bb_data.terminator = Some(Terminator {
|
||||
source_info: terminator.source_info,
|
||||
kind: TerminatorKind::Goto { target: target.unwrap() },
|
||||
});
|
||||
local
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), allow(unused))]
|
||||
|
@ -1085,10 +992,11 @@ fn compute_layout<'tcx>(
|
|||
// Build the coroutine variant field list.
|
||||
// Create a map from local indices to coroutine struct indices.
|
||||
let mut variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> =
|
||||
iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect();
|
||||
iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect();
|
||||
let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size());
|
||||
for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() {
|
||||
let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx);
|
||||
let variant_index =
|
||||
VariantIdx::from(CoroutineArgs::RESERVED_VARIANTS + suspension_point_idx);
|
||||
let mut fields = IndexVec::new();
|
||||
for (idx, saved_local) in live_locals.iter().enumerate() {
|
||||
fields.push(saved_local);
|
||||
|
@ -1183,12 +1091,10 @@ fn elaborate_coroutine_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
source_info,
|
||||
kind: TerminatorKind::Drop { place, target, unwind, replace: _ },
|
||||
} => {
|
||||
if let Some(local) = place.as_local() {
|
||||
if local == SELF_ARG {
|
||||
(target, unwind, source_info)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if let Some(local) = place.as_local()
|
||||
&& local == SELF_ARG
|
||||
{
|
||||
(target, unwind, source_info)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
@ -1237,7 +1143,7 @@ fn create_coroutine_drop_shim<'tcx>(
|
|||
|
||||
let mut cases = create_cases(&mut body, transform, Operation::Drop);
|
||||
|
||||
cases.insert(0, (UNRESUMED, drop_clean));
|
||||
cases.insert(0, (CoroutineArgs::UNRESUMED, drop_clean));
|
||||
|
||||
// The returned state and the poisoned state fall through to the default
|
||||
// case which is just to return
|
||||
|
@ -1387,7 +1293,9 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
if can_unwind {
|
||||
let source_info = SourceInfo::outermost(body.span);
|
||||
let poison_block = body.basic_blocks_mut().push(BasicBlockData {
|
||||
statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
|
||||
statements: vec![
|
||||
transform.set_discr(VariantIdx::new(CoroutineArgs::POISONED), source_info),
|
||||
],
|
||||
terminator: Some(Terminator { source_info, kind: TerminatorKind::UnwindResume }),
|
||||
is_cleanup: true,
|
||||
});
|
||||
|
@ -1419,13 +1327,16 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn};
|
||||
|
||||
// Jump to the entry point on the unresumed
|
||||
cases.insert(0, (UNRESUMED, START_BLOCK));
|
||||
cases.insert(0, (CoroutineArgs::UNRESUMED, START_BLOCK));
|
||||
|
||||
// Panic when resumed on the returned or poisoned state
|
||||
if can_unwind {
|
||||
cases.insert(
|
||||
1,
|
||||
(POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(transform.coroutine_kind))),
|
||||
(
|
||||
CoroutineArgs::POISONED,
|
||||
insert_panic_block(tcx, body, ResumedAfterPanic(transform.coroutine_kind)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1440,7 +1351,7 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
transform.insert_none_ret_block(body)
|
||||
}
|
||||
};
|
||||
cases.insert(1, (RETURNED, block));
|
||||
cases.insert(1, (CoroutineArgs::RETURNED, block));
|
||||
}
|
||||
|
||||
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
||||
|
@ -1624,7 +1535,7 @@ fn check_field_tys_sized<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||
impl<'tcx> crate::MirPass<'tcx> for StateTransform {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let Some(old_yield_ty) = body.yield_ty() else {
|
||||
// This only applies to coroutines
|
||||
|
|
|
@ -207,11 +207,12 @@ pub fn coroutine_by_move_body_def_id<'tcx>(
|
|||
|
||||
let mut by_move_body = body.clone();
|
||||
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
|
||||
dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
|
||||
|
||||
let body_def = tcx.create_def(coroutine_def_id, kw::Empty, DefKind::SyntheticCoroutineBody);
|
||||
// This will always be `{closure#1}`, since the original coroutine is `{closure#0}`.
|
||||
let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody);
|
||||
by_move_body.source =
|
||||
mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id()));
|
||||
dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(()));
|
||||
|
||||
// Inherited from the by-ref coroutine.
|
||||
body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone());
|
||||
|
|
|
@ -28,14 +28,13 @@ use tracing::{debug, debug_span, instrument, trace};
|
|||
use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
|
||||
use crate::coverage::graph::CoverageGraph;
|
||||
use crate::coverage::mappings::ExtractedMappings;
|
||||
use crate::MirPass;
|
||||
|
||||
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
|
||||
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
|
||||
/// to construct the coverage map.
|
||||
pub struct InstrumentCoverage;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
|
||||
impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.instrument_coverage()
|
||||
}
|
||||
|
|
|
@ -8,11 +8,9 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::MirPass;
|
||||
|
||||
pub struct CtfeLimit;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for CtfeLimit {
|
||||
impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
|
||||
#[instrument(skip(self, _tcx, body))]
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let doms = body.basic_blocks.dominators();
|
||||
|
|
|
@ -28,7 +28,7 @@ const PLACE_LIMIT: usize = 100;
|
|||
|
||||
pub struct DataflowConstProp;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DataflowConstProp {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 3
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
let borrowed_locals = borrowed_locals(body);
|
||||
|
||||
// If the user requests complete debuginfo, mark the locals that appear in it as live, so
|
||||
// we don't remove assignements to them.
|
||||
// we don't remove assignments to them.
|
||||
let mut always_live = debuginfo_locals(body);
|
||||
always_live.union(&borrowed_locals);
|
||||
|
||||
|
@ -132,7 +132,7 @@ pub enum DeadStoreElimination {
|
|||
Final,
|
||||
}
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
|
||||
fn name(&self) -> &'static str {
|
||||
match self {
|
||||
DeadStoreElimination::Initial => "DeadStoreElimination-initial",
|
||||
|
|
|
@ -15,7 +15,7 @@ use super::simplify::simplify_cfg;
|
|||
|
||||
pub struct DeduplicateBlocks;
|
||||
|
||||
impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
|
||||
impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
|
||||
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
|
||||
sess.mir_opt_level() >= 4
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue