1
Fork 0

Merge from rustc

This commit is contained in:
The Miri Cronjob Bot 2024-09-06 05:09:32 +00:00
commit 2fccb4b358
739 changed files with 5703 additions and 2574 deletions

View file

@ -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>

View file

@ -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]]

View file

@ -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)
==========================

View file

@ -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

View file

@ -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

View file

@ -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`

View file

@ -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),

View file

@ -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) {

View file

@ -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.

View file

@ -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

View file

@ -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).

View file

@ -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 {

View file

@ -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>;

View file

@ -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}")

View file

@ -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.

View file

@ -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 },

View file

@ -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,

View file

@ -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)

View file

@ -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() {

View file

@ -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");
}
}

View file

@ -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();

View file

@ -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 },

View file

@ -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};

View file

@ -14,6 +14,7 @@
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(yeet_expr)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end
pub mod check_consts;

View file

@ -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;

View file

@ -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;

View file

@ -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.

View file

@ -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)
}

View file

@ -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',

View file

@ -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;

View file

@ -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:
```

View file

@ -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

View file

@ -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
// |

View file

@ -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 => {

View file

@ -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

View file

@ -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)),

View file

@ -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,

View file

@ -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)

View file

@ -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 {

View file

@ -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

View file

@ -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!(

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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");

View file

@ -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,

View file

@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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")

View file

@ -20,4 +20,5 @@ nightly = [
"dep:rustc_macros",
"rustc_index_macros/nightly",
]
rustc_randomized_layouts = []
# tidy-alphabetical-end

View file

@ -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>());
};
}

View file

@ -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,

View file

@ -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`).
///

View file

@ -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)]);

View file

@ -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.
//

View file

@ -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 =

View file

@ -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

View file

@ -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)

View file

@ -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,
}
}

View file

@ -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) =>

View file

@ -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)]

View file

@ -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 {

View file

@ -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

View file

@ -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 {

View file

@ -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"

View file

@ -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)

View file

@ -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 {

View file

@ -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>>>>,

View file

@ -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

View file

@ -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,

View file

@ -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,
}

View file

@ -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.
///

View file

@ -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) {

View file

@ -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

View file

@ -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!(

View file

@ -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,

View file

@ -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| {

View file

@ -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

View file

@ -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()
}

View file

@ -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 {

View file

@ -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,
}
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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) }],

View file

@ -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
}

View file

@ -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);
}

View file

@ -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" {

View file

@ -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);

View file

@ -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 });
}
}
}

View file

@ -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() {

View file

@ -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
}

View file

@ -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

View file

@ -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());

View file

@ -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()
}

View file

@ -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();

View file

@ -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
}

View file

@ -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",

View file

@ -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