diff --git a/.gitmodules b/.gitmodules
index b5250d493864e..926807336d791 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -47,3 +47,7 @@
path = src/tools/rustc-perf
url = https://github.com/rust-lang/rustc-perf.git
shallow = true
+[submodule "src/tools/enzyme"]
+ path = src/tools/enzyme
+ url = https://github.com/EnzymeAD/Enzyme.git
+ shallow = true
diff --git a/Cargo.lock b/Cargo.lock
index ce78d921244fc..d67141996827b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3569,6 +3569,7 @@ dependencies = [
"rustc_hir_pretty",
"rustc_hir_typeck",
"rustc_incremental",
+ "rustc_index",
"rustc_infer",
"rustc_interface",
"rustc_lint",
diff --git a/RELEASES.md b/RELEASES.md
index 6aba476103e7f..b49470c307569 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -34,7 +34,6 @@ Compiler
- [Add Tier 3 `std` Xtensa targets:](https://github.com/rust-lang/rust/pull/126380/) `xtensa-esp32-espidf`, `xtensa-esp32s2-espidf`, `xtensa-esp32s3-espidf`
- [Add Tier 3 i686 Redox OS target:](https://github.com/rust-lang/rust/pull/126192/) `i686-unknown-redox`
- [Promote `arm64ec-pc-windows-msvc` to Tier 2.](https://github.com/rust-lang/rust/pull/126039/)
- - [Promote `wasm32-wasip2` to Tier 2.](https://github.com/rust-lang/rust/pull/126967/)
- [Promote `loongarch64-unknown-linux-musl` to Tier 2 with host tools.](https://github.com/rust-lang/rust/pull/126298/)
- [Enable full tools and profiler for LoongArch Linux targets.](https://github.com/rust-lang/rust/pull/127078/)
- [Unconditionally warn on usage of `wasm32-wasi`.](https://github.com/rust-lang/rust/pull/126662/) (see compatibility note below)
@@ -100,6 +99,9 @@ Compatibility Notes
The reason is that these types have different roles: `std::panic::PanicHookInfo` is the argument to the [panic hook](https://doc.rust-lang.org/stable/std/panic/fn.set_hook.html) in std context (where panics can have an arbitrary payload), while `core::panic::PanicInfo` is the argument to the [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) in no_std context (where panics always carry a formatted *message*). Separating these types allows us to add more useful methods to these types, such as `std::panic::PanicHookInfo::payload_as_str()` and `core::panic::PanicInfo::message()`.
* The new sort implementations may panic if a type's implementation of [`Ord`](https://doc.rust-lang.org/std/cmp/trait.Ord.html) (or the given comparison function) does not implement a [total order](https://en.wikipedia.org/wiki/Total_order) as the trait requires. `Ord`'s supertraits (`PartialOrd`, `Eq`, and `PartialEq`) must also be consistent. The previous implementations would not "notice" any problem, but the new implementations have a good chance of detecting inconsistencies, throwing a panic rather than returning knowingly unsorted data.
+* [In very rare cases, a change in the internal evaluation order of the trait
+ solver may result in new fatal overflow errors.](https://github.com/rust-lang/rust/pull/126128)
+
@@ -112,6 +114,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)
+===========================
+
+
+
+- [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)
==========================
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 5008069542f1f..a2fc9d5c408e3 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -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
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 5160b4ed0a2ac..7432768be4a58 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -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 = 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
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index df29b3d54f0fb..be42bc8493243 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -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()`.
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`
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 91b02a36d0046..c720b0928feb0 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -662,9 +662,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
// `&dyn Trait`
ty::Ref(_, ty, _) if ty.is_trait() => true,
// `Box`
- _ if ty.is_box() && ty.boxed_ty().is_trait() => {
+ _ if ty.boxed_ty().is_some_and(Ty::is_trait) => {
true
}
+
// `dyn Trait`
_ if ty.is_trait() => true,
// Anything else.
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 5ab66963409a8..878ce6162e0f9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -345,9 +345,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
variant_index: Option,
including_tuple_field: IncludingTupleField,
) -> Option {
- if ty.is_box() {
+ if let Some(boxed_ty) = ty.boxed_ty() {
// If the type is a box, the field is described from the boxed type
- self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
+ self.describe_field_from_ty(boxed_ty, field, variant_index, including_tuple_field)
} else {
match *ty.kind() {
ty::Adt(def, _) => {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index ffb350b1d1f0f..d40dcfa58054a 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2522,7 +2522,7 @@ mod diags {
}
pub(crate) fn emit_errors(&mut self) -> Option {
- let mut res = None;
+ let mut res = self.infcx.tainted_by_errors();
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 224f8d5c893d7..3c9a43883ad64 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1979,19 +1979,76 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
match cast_kind {
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer) => {
- let fn_sig = op.ty(body, tcx).fn_sig(tcx);
+ let src_sig = op.ty(body, tcx).fn_sig(tcx);
+
+ // HACK: This shouldn't be necessary... We can remove this when we actually
+ // get binders with where clauses, then elaborate implied bounds into that
+ // binder, and implement a higher-ranked subtyping algorithm that actually
+ // respects these implied bounds.
+ //
+ // This protects against the case where we are casting from a higher-ranked
+ // fn item to a non-higher-ranked fn pointer, where the cast throws away
+ // implied bounds that would've needed to be checked at the call site. This
+ // only works when we're casting to a non-higher-ranked fn ptr, since
+ // placeholders in the target signature could have untracked implied
+ // bounds, resulting in incorrect errors.
+ //
+ // We check that this signature is WF before subtyping the signature with
+ // the target fn sig.
+ if src_sig.has_bound_regions()
+ && let ty::FnPtr(target_fn_tys, target_hdr) = *ty.kind()
+ && let target_sig = target_fn_tys.with(target_hdr)
+ && let Some(target_sig) = target_sig.no_bound_vars()
+ {
+ let src_sig = self.infcx.instantiate_binder_with_fresh_vars(
+ span,
+ BoundRegionConversionTime::HigherRankedType,
+ src_sig,
+ );
+ let src_ty = Ty::new_fn_ptr(self.tcx(), ty::Binder::dummy(src_sig));
+ self.prove_predicate(
+ ty::ClauseKind::WellFormed(src_ty.into()),
+ location.to_locations(),
+ ConstraintCategory::Cast { unsize_to: None },
+ );
+
+ let src_ty = self.normalize(src_ty, location);
+ if let Err(terr) = self.sub_types(
+ src_ty,
+ *ty,
+ location.to_locations(),
+ ConstraintCategory::Cast { unsize_to: None },
+ ) {
+ span_mirbug!(
+ self,
+ rvalue,
+ "equating {:?} with {:?} yields {:?}",
+ target_sig,
+ src_sig,
+ terr
+ );
+ };
+ }
+
+ let src_ty = Ty::new_fn_ptr(tcx, src_sig);
+ // HACK: We want to assert that the signature of the source fn is
+ // well-formed, because we don't enforce that via the WF of FnDef
+ // types normally. This should be removed when we improve the tracking
+ // of implied bounds of fn signatures.
+ self.prove_predicate(
+ ty::ClauseKind::WellFormed(src_ty.into()),
+ location.to_locations(),
+ ConstraintCategory::Cast { unsize_to: None },
+ );
// The type that we see in the fcx is like
// `foo::<'a, 'b>`, where `foo` is the path to a
// function definition. When we extract the
// signature, it comes from the `fn_sig` query,
// and hence may contain unnormalized results.
- let fn_sig = self.normalize(fn_sig, location);
-
- let ty_fn_ptr_from = Ty::new_fn_ptr(tcx, fn_sig);
-
+ let src_ty = self.normalize(src_ty, location);
if let Err(terr) = self.sub_types(
- ty_fn_ptr_from,
+ src_ty,
*ty,
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
@@ -2000,7 +2057,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
- ty_fn_ptr_from,
+ src_ty,
ty,
terr
);
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 9eabe817359c0..164be73f49296 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -29,7 +29,8 @@ use rustc_macros::extension;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
- self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, TyCtxt,
+ self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty,
+ TyCtxt, TypeVisitableExt,
};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::{kw, sym};
@@ -688,7 +689,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
defining_ty: DefiningTy<'tcx>,
) -> ty::Binder<'tcx, &'tcx ty::List>> {
let tcx = self.infcx.tcx;
- match defining_ty {
+
+ let inputs_and_output = match defining_ty {
DefiningTy::Closure(def_id, args) => {
assert_eq!(self.mir_def.to_def_id(), def_id);
let closure_sig = args.as_closure().sig();
@@ -798,6 +800,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// "output" (the type of the constant).
assert_eq!(self.mir_def.to_def_id(), def_id);
let ty = tcx.type_of(self.mir_def).instantiate_identity();
+
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
@@ -807,7 +810,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let ty = args.as_inline_const().ty();
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
+ };
+
+ // FIXME(#129952): We probably want a more principled approach here.
+ if let Err(terr) = inputs_and_output.skip_binder().error_reported() {
+ self.infcx.set_tainted_by_errors(terr);
}
+
+ inputs_and_output
}
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index b143e28c5f9cc..d60122fccee21 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -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
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 17a9630c6557b..d231b103964b6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -456,7 +456,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) ->
if def.is_box()
&& args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
{
- build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
+ build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id)
}
ty::FnDef(..) | ty::FnPtr(..) => build_subroutine_type_di_node(cx, unique_type_id),
ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id),
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a300f5f707a88..05fb77a193af3 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -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 {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 138cc3219aa08..3bf4d4964082f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -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>;
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index d94c6f8ddcec3..91fd9905f63cc 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -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.
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 2ef860fc336d6..73283cafb4947 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -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 },
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 82438eb5e7828..568a9a3a637be 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -189,7 +189,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ty::Ref(_, ty, _) => *ty,
ty::RawPtr(ty, _) => *ty,
// We only accept `Box` with the default allocator.
- _ if ty.is_box_global(*self.tcx) => ty.boxed_ty(),
+ _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(),
_ => return Ok(None),
}))
};
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index 0f2c0eee27d2f..aaa95f6b7f19e 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -57,6 +57,7 @@ impl Steal {
///
/// This should not be used within rustc as it leaks information not tracked
/// by the query system, breaking incremental compilation.
+ #[cfg_attr(not(bootstrap), rustc_lint_untracked_query_information)]
pub fn is_stolen(&self) -> bool {
self.value.borrow().is_none()
}
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 91cbffcd7072b..6d6d3f35a4b1b 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -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',
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e49ae60e890ba..cb2fa6e9d746b 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -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;
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e2491922b8df6..e86421f2150db 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -793,6 +793,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_lint_query_instability, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
),
+ // Used by the `rustc::untracked_query_information` lint to warn methods which
+ // might not be stable during incremental compilation.
+ rustc_attr!(
+ rustc_lint_untracked_query_information, Normal, template!(Word),
+ WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+ ),
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
// APIs. Any function with this attribute will be checked by that lint.
rustc_attr!(
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index cd6adbda039b2..fba65883550b5 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -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.
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index f83eac7cd6c4d..3627faf8dfc57 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -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`.
+/// 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`.
///
/// 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,
) -> 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,
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index bd8b43e28e540..9fce927e2c7f2 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -93,7 +93,8 @@ impl<'tcx> InherentCollect<'tcx> {
}
}
- if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) {
+ if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer)
+ {
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else {
bug!("unexpected self type: {:?}", self_ty);
@@ -132,7 +133,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
}
- if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsCandidateKey) {
+ if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::InstantiateWithInfer) {
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else {
bug!("unexpected primitive type: {:?}", ty);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 7be45463f1512..149bc6d26984d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -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`
// and suggest `Trait0`.
+ // 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` 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`
+ // suggestion.
+ let suggestion = if borrowed {
+ vec![(ty.span, format!("Box"))]
+ } else {
vec![
(ty.span.shrink_to_lo(), "Box".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!(
diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index 0790c6f9a5992..ac5e1040803e0 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -63,8 +63,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Instead, the problem is that the array-into_iter hack will no longer
// apply in Rust 2021.
(ARRAY_INTO_ITER, "2021")
- } else if self_ty.is_box()
- && self_ty.boxed_ty().is_slice()
+ } else if self_ty.boxed_ty().is_some_and(Ty::is_slice)
&& !span.at_least_rust_2024()
{
// In this case, it wasn't really a prelude addition that was the problem.
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 0cf5403b3c085..3ba3429cbb331 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -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,
@@ -715,7 +715,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
}
fn assemble_inherent_candidates_for_incoherent_ty(&mut self, self_ty: Ty<'tcx>) {
- let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsCandidateKey) else {
+ let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::InstantiateWithInfer) else {
bug!("unexpected incoherent type: {:?}", self_ty)
};
for &impl_def_id in self.tcx.incoherent_impls(simp).into_iter().flatten() {
@@ -1485,8 +1485,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
// Some trait methods are excluded for boxed slices before 2024.
// (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
- if self_ty.is_box()
- && self_ty.boxed_ty().is_slice()
+ if self_ty.boxed_ty().is_some_and(Ty::is_slice)
&& !method_name.span.at_least_rust_2024()
{
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9ea57e4aa6168..14ad5830111b4 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2235,8 +2235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let target_ty = self
.autoderef(sugg_span, rcvr_ty)
.find(|(rcvr_ty, _)| {
- DeepRejectCtxt::new(self.tcx, TreatParams::ForLookup)
- .types_may_unify(*rcvr_ty, impl_ty)
+ DeepRejectCtxt::relate_rigid_infer(self.tcx).types_may_unify(*rcvr_ty, impl_ty)
})
.map_or(impl_ty, |(ty, _)| ty)
.peel_refs();
@@ -2498,7 +2497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter()
.any(|info| self.associated_value(info.def_id, item_name).is_some());
let found_assoc = |ty: Ty<'tcx>| {
- simplify_type(tcx, ty, TreatParams::AsCandidateKey)
+ simplify_type(tcx, ty, TreatParams::InstantiateWithInfer)
.and_then(|simp| {
tcx.incoherent_impls(simp)
.into_iter()
@@ -3963,7 +3962,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// cases where a positive bound implies a negative impl.
(candidates, Vec::new())
} else if let Some(simp_rcvr_ty) =
- simplify_type(self.tcx, rcvr_ty, TreatParams::ForLookup)
+ simplify_type(self.tcx, rcvr_ty, TreatParams::AsRigid)
{
let mut potential_candidates = Vec::new();
let mut explicitly_negative = Vec::new();
@@ -3981,7 +3980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.any(|header| {
let imp = header.trait_ref.instantiate_identity();
let imp_simp =
- simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
+ simplify_type(self.tcx, imp.self_ty(), TreatParams::AsRigid);
imp_simp.is_some_and(|s| s == simp_rcvr_ty)
})
{
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index 92ea3f278dc43..f7d18f84e3452 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -20,4 +20,5 @@ nightly = [
"dep:rustc_macros",
"rustc_index_macros/nightly",
]
+rustc_randomized_layouts = []
# tidy-alphabetical-end
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index f773b5b46adae..52f354b8ecaff 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -33,8 +33,19 @@ pub use vec::IndexVec;
///
///
#[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>());
+ };
+}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 42fed98df0101..50422df8ee648 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -808,7 +808,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(mir_opt_level, Some(4));
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, false);
- tracked!(next_solver, Some(NextSolverConfig { coherence: true, globally: false }));
+ tracked!(next_solver, NextSolverConfig { coherence: true, globally: true });
tracked!(no_generate_arange_section, true);
tracked!(no_jump_tables, true);
tracked!(no_link, true);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 353345958337c..759320b9eb65f 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -699,6 +699,9 @@ lint_ptr_null_checks_ref = references are not nullable, so checking them for nul
lint_query_instability = using `{$query}` can result in unstable query results
.note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+lint_query_untracked = `{$method}` accesses information that is not tracked by the query system
+ .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+
lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
lint_range_use_inclusive_range = use an inclusive range instead
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index 8824e1dfe50d8..c43c650a9f912 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -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,
+ in_scope_parameters: FxIndexMap,
+ variances: LazyCell, VarFn>,
+ outlives_env: LazyCell, OutlivesFn>,
seen: FxIndexSet,
}
-impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> {
- fn visit_binder>>(
- &mut self,
- t: &ty::Binder<'tcx, T>,
- ) -> Self::Result {
+impl<'tcx, VarFn, OutlivesFn> TypeVisitor>
+ for VisitOpaqueTypes<'tcx, VarFn, OutlivesFn>
+where
+ VarFn: FnOnce() -> FxHashMap,
+ OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
+{
+ fn visit_binder>>(&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> 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> 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> 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> 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,
+ ambient_variance: ty::Variance,
+ generics: &'tcx ty::Generics,
+}
+
+impl<'tcx> TypeRelation> for FunctionalVariances<'tcx> {
+ fn cx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn relate_with_variance>>(
+ &mut self,
+ variance: rustc_type_ir::Variance,
+ _: ty::VarianceDiagInfo>,
+ 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(
+ &mut self,
+ a: ty::Binder<'tcx, T>,
+ b: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+ where
+ T: Relate>,
+ {
+ 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,
+ }
+}
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 2e8116b8ba892..9d637c1eb7f84 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -17,8 +17,8 @@ use tracing::debug;
use crate::lints::{
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
- NonGlobImportTypeIrInherent, QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag,
- TykindKind, TypeIrInherentUsage, UntranslatableDiag,
+ NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked, SpanUseEqCtxtDiag, TyQualified,
+ TykindDiag, TykindKind, TypeIrInherentUsage, UntranslatableDiag,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
@@ -88,7 +88,18 @@ declare_tool_lint! {
report_in_external_macro: true
}
-declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
+declare_tool_lint! {
+ /// The `untracked_query_information` lint detects use of methods which leak information not
+ /// tracked by the query system, such as whether a `Steal` value has already been stolen. In
+ /// order not to break incremental compilation, such methods must be used very carefully or not
+ /// at all.
+ pub rustc::UNTRACKED_QUERY_INFORMATION,
+ Allow,
+ "require explicit opt-in when accessing information not tracked by the query system",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]);
impl LateLintPass<'_> for QueryStability {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -102,6 +113,13 @@ impl LateLintPass<'_> for QueryStability {
QueryInstability { query: cx.tcx.item_name(def_id) },
);
}
+ if cx.tcx.has_attr(def_id, sym::rustc_lint_untracked_query_information) {
+ cx.emit_span_lint(
+ UNTRACKED_QUERY_INFORMATION,
+ span,
+ QueryUntracked { method: cx.tcx.item_name(def_id) },
+ );
+ }
}
}
}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c5a5c5b30afef..a9627e9b78907 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -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)]
@@ -609,6 +610,7 @@ fn register_internals(store: &mut LintStore) {
vec![
LintId::of(DEFAULT_HASH_TYPES),
LintId::of(POTENTIAL_QUERY_INSTABILITY),
+ LintId::of(UNTRACKED_QUERY_INFORMATION),
LintId::of(USAGE_OF_TY_TYKIND),
LintId::of(PASS_BY_VALUE),
LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7ca282b7c8541..9050f36acba7b 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -894,6 +894,13 @@ pub(crate) struct QueryInstability {
pub query: Symbol,
}
+#[derive(LintDiagnostic)]
+#[diag(lint_query_untracked)]
+#[note]
+pub(crate) struct QueryUntracked {
+ pub method: Symbol,
+}
+
#[derive(LintDiagnostic)]
#[diag(lint_span_use_eq_ctxt)]
pub(crate) struct SpanUseEqCtxtDiag;
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index bb9c7d85c2efc..bb122509d0a89 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -94,12 +94,9 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
fn is_ref_to_array(ty: Ty<'_>) -> bool {
if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false }
}
- fn is_boxed_slice(ty: Ty<'_>) -> bool {
- ty.is_box() && ty.boxed_ty().is_slice()
- }
fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool {
if let ty::Ref(_, pointee_ty, _) = *ty.kind() {
- is_boxed_slice(pointee_ty)
+ pointee_ty.boxed_ty().is_some_and(Ty::is_slice)
} else {
false
}
@@ -119,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
.iter()
.copied()
.take_while(|ty| !is_ref_to_boxed_slice(*ty))
- .position(|ty| is_boxed_slice(ty))
+ .position(|ty| ty.boxed_ty().is_some_and(Ty::is_slice))
{
(BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0)
} else {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index f2f7c0eaa4df8..b5e501b92f0d6 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1304,8 +1304,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match *ty.kind() {
ty::Adt(def, args) => {
- if def.is_box() && matches!(self.mode, CItemKind::Definition) {
- if ty.boxed_ty().is_sized(tcx, self.cx.param_env) {
+ if let Some(boxed) = ty.boxed_ty()
+ && matches!(self.mode, CItemKind::Definition)
+ {
+ if boxed.is_sized(tcx, self.cx.param_env) {
return FfiSafe;
} else {
return FfiUnsafe {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 761d30bac715a..b7f7b782c7722 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -283,9 +283,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
match *ty.kind() {
- ty::Adt(..) if ty.is_box() => {
- let boxed_ty = ty.boxed_ty();
- is_ty_must_use(cx, boxed_ty, expr, span)
+ ty::Adt(..) if let Some(boxed) = ty.boxed_ty() => {
+ is_ty_must_use(cx, boxed, expr, span)
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
}
ty::Adt(def, args) if cx.tcx.is_lang_item(def.did(), LangItem::Pin) => {
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 7063f488209ea..25d33126754af 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -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"
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 1264510a831a9..53da07aeaa695 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -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 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 88256c4db04ec..83bad59825c05 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -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 {
@@ -2033,7 +2033,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
- TreatParams::AsCandidateKey,
+ TreatParams::InstantiateWithInfer,
);
trait_impls
.entry(trait_ref.def_id)
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a84923130c3ab..8180a507a514d 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -390,6 +390,8 @@ define_tables! {
explicit_item_bounds: Table, Span)>>,
explicit_item_super_predicates: Table, Span)>>,
inferred_outlives_of: Table, Span)>>,
+ explicit_super_predicates_of: Table, Span)>>,
+ explicit_implied_predicates_of: Table, Span)>>,
inherent_impls: Table>,
associated_types_for_impl_traits_in_associated_fn: Table>,
associated_type_for_effects: Table>>,
@@ -419,10 +421,6 @@ define_tables! {
lookup_deprecation_entry: Table>,
explicit_predicates_of: Table>>,
generics_of: Table>,
- explicit_super_predicates_of: Table, 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, Span)>>,
type_of: Table>>>,
variances_of: Table>,
fn_sig: Table>>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 69e3b703ccee1..b23589afb5874 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -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
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 7b90191503702..081a23b6ff317 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -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> = {
- 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::();
- 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.
///
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 9906be60e3e95..a98e6943d68ee 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -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) {
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 748ca047754a9..22a4b688c517c 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1307,6 +1307,9 @@ pub enum Rvalue<'tcx> {
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
/// ill-formed for places of other types.
+ ///
+ /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only
+ /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing.
Len(Place<'tcx>),
/// Performs essentially all of the casts that can be performed via `as`.
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index c9bd702cce340..0320a91d142b7 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -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::>() > 64 {
panic!("{}", concat!(
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 20828067c469c..2a3008897c676 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -426,7 +426,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
let simp = ty::fast_reject::simplify_type(
tcx,
self_ty,
- ty::fast_reject::TreatParams::ForLookup,
+ ty::fast_reject::TreatParams::AsRigid,
)
.unwrap();
consider_impls_for_simplified_type(simp);
@@ -3128,11 +3128,11 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn next_trait_solver_globally(self) -> bool {
- self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally)
+ self.sess.opts.unstable_opts.next_solver.globally
}
pub fn next_trait_solver_in_coherence(self) -> bool {
- self.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.coherence)
+ self.sess.opts.unstable_opts.next_solver.coherence
}
pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 91344c4e39c8b..2945a0be424f8 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -3,6 +3,14 @@ pub use rustc_type_ir::fast_reject::*;
use super::TyCtxt;
-pub type DeepRejectCtxt<'tcx> = rustc_type_ir::fast_reject::DeepRejectCtxt>;
+pub type DeepRejectCtxt<
+ 'tcx,
+ const INSTANTIATE_LHS_WITH_INFER: bool,
+ const INSTANTIATE_RHS_WITH_INFER: bool,
+> = rustc_type_ir::fast_reject::DeepRejectCtxt<
+ TyCtxt<'tcx>,
+ INSTANTIATE_LHS_WITH_INFER,
+ INSTANTIATE_RHS_WITH_INFER,
+>;
pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType;
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 698104b0462e3..dd00db8635f4d 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -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| {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index d0a9039441dc4..8cec8eac1898a 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1075,11 +1075,13 @@ where
// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
// will still be `None`.
if let Some(ref mut pointee) = result {
- if offset.bytes() == 0 && this.ty.is_box() {
+ if offset.bytes() == 0
+ && let Some(boxed_ty) = this.ty.boxed_ty()
+ {
debug_assert!(pointee.safe.is_none());
let optimize = tcx.sess.opts.optimize != OptLevel::No;
pointee.safe = Some(PointerKind::Box {
- unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
+ unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()),
global: this.ty.is_box_global(tcx),
});
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cd94c0afad0a9..ee70a6346d920 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -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);
}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 89ef30fa768e0..1f4f2c62d7084 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1170,14 +1170,19 @@ impl<'tcx> Ty<'tcx> {
}
}
- /// Panics if called on any type other than `Box`.
- pub fn boxed_ty(self) -> Ty<'tcx> {
+ pub fn boxed_ty(self) -> Option> {
match self.kind() {
- Adt(def, args) if def.is_box() => args.type_at(0),
- _ => bug!("`boxed_ty` is called on non-box type {:?}", self),
+ Adt(def, args) if def.is_box() => Some(args.type_at(0)),
+ _ => None,
}
}
+ /// Panics if called on any type other than `Box`.
+ pub fn expect_boxed_ty(self) -> Ty<'tcx> {
+ self.boxed_ty()
+ .unwrap_or_else(|| bug!("`expect_boxed_ty` is called on non-box type {:?}", self))
+ }
+
/// A scalar type is one that denotes an atomic datum, with no sub-components.
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
/// contents are abstract to rustc.)
@@ -1323,7 +1328,7 @@ impl<'tcx> Ty<'tcx> {
/// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
pub fn builtin_deref(self, explicit: bool) -> Option> {
match *self.kind() {
- Adt(def, _) if def.is_box() => Some(self.boxed_ty()),
+ _ if let Some(boxed) = self.boxed_ty() => Some(boxed),
Ref(_, ty, _) => Some(ty),
RawPtr(ty, _) if explicit => Some(ty),
_ => None,
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index dfb137f738f1e..82690f70e5f18 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -168,9 +168,9 @@ impl<'tcx> TyCtxt<'tcx> {
// whose outer level is not a parameter or projection. Especially for things like
// `T: Clone` this is incredibly useful as we would otherwise look at all the impls
// of `Clone` for `Option`, `Vec`, `ConcreteType` and so on.
- // Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
- // `TreatParams::AsCandidateKey` while actually adding them.
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::ForLookup) {
+ // Note that we're using `TreatParams::AsRigid` to query `non_blanket_impls` while using
+ // `TreatParams::InstantiateWithInfer` while actually adding them.
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsRigid) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
f(impl_def_id);
@@ -190,7 +190,9 @@ impl<'tcx> TyCtxt<'tcx> {
self_ty: Ty<'tcx>,
) -> impl Iterator- + 'tcx {
let impls = self.trait_impls_of(trait_def_id);
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
+ if let Some(simp) =
+ fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer)
+ {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
return impls.iter().copied();
}
@@ -239,7 +241,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
let impl_self_ty = tcx.type_of(impl_def_id).instantiate_identity();
if let Some(simplified_self_ty) =
- fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::AsCandidateKey)
+ fast_reject::simplify_type(tcx, impl_self_ty, TreatParams::InstantiateWithInfer)
{
impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
} else {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index efbccca77c1f0..d70ff8258d04c 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1628,7 +1628,7 @@ impl<'tcx> ExplicitSelf<'tcx> {
_ if is_self_ty(self_arg_ty) => ByValue,
ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl),
ty::RawPtr(ty, mutbl) if is_self_ty(ty) => ByRawPointer(mutbl),
- ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => ByBox,
+ _ if self_arg_ty.boxed_ty().is_some_and(is_self_ty) => ByBox,
_ => Other,
}
}
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index 2038d3f84484e..223b2b3bfe4de 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -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,
- }
-}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 0171cc8591809..8c3e6f49b1618 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -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 {
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 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);
}
}
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index edb6bc4fbea2f..e4bc6b3efe422 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -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);
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index df5312d155c13..78e850de3c772 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -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);
}
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index e503119a3495b..4a8196aeff5b0 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -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);
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 79bc21cab147e..2e12064fe7351 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -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
}
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index 04204c68f7b76..369f6c6008440 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -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);
}
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index ad362f22ce197..2e072aa262aac 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -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" {
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 1f615c9d8d1a2..fb03323e37e6e 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -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);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index eb76a39be57ff..2f957de7e78d8 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -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);
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 08c9f9f08e6b2..2f3be1e425d8d 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -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() {
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 5c267f853783f..85d25ca22318d 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -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
}
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 80ba1c4266811..eefb748e49d51 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1535,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
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index ebe8d2eff4ff3..cf39c136b01a3 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -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());
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index bba354d29363d..4edba61fdec9e 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -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()
}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index fcc774503f45a..b904b0d2599b1 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -3,7 +3,7 @@ use std::collections::VecDeque;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir;
-use rustc_span::Span;
+use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span};
use tracing::{debug, debug_span, instrument};
use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
@@ -25,7 +25,7 @@ pub(super) fn extract_refined_covspans(
// First, perform the passes that need macro information.
covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb));
- remove_unwanted_macro_spans(&mut covspans);
+ remove_unwanted_expansion_spans(&mut covspans);
split_visible_macro_spans(&mut covspans);
// We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`.
@@ -76,18 +76,24 @@ pub(super) fn extract_refined_covspans(
/// invocation, which is unhelpful. Keeping only the first such span seems to
/// give better mappings, so remove the others.
///
+/// Similarly, `await` expands to a branch on the discriminant of `Poll`, which
+/// leads to incorrect coverage if the `Future` is immediately ready (#98712).
+///
/// (The input spans should be sorted in BCB dominator order, so that the
/// retained "first" span is likely to dominate the others.)
-fn remove_unwanted_macro_spans(covspans: &mut Vec) {
- let mut seen_macro_spans = FxHashSet::default();
+fn remove_unwanted_expansion_spans(covspans: &mut Vec) {
+ let mut deduplicated_spans = FxHashSet::default();
+
covspans.retain(|covspan| {
- // Ignore (retain) non-macro-expansion spans.
- if covspan.visible_macro.is_none() {
- return true;
+ match covspan.expn_kind {
+ // Retain only the first await-related or macro-expanded covspan with this span.
+ Some(ExpnKind::Desugaring(kind)) if kind == DesugaringKind::Await => {
+ deduplicated_spans.insert(covspan.span)
+ }
+ Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span),
+ // Ignore (retain) other spans.
+ _ => true,
}
-
- // Retain only the first macro-expanded covspan with this span.
- seen_macro_spans.insert(covspan.span)
});
}
@@ -99,7 +105,9 @@ fn split_visible_macro_spans(covspans: &mut Vec) {
let mut extra_spans = vec![];
covspans.retain(|covspan| {
- let Some(visible_macro) = covspan.visible_macro else { return true };
+ let Some(ExpnKind::Macro(MacroKind::Bang, visible_macro)) = covspan.expn_kind else {
+ return true;
+ };
let split_len = visible_macro.as_str().len() as u32 + 1;
let (before, after) = covspan.span.split_at(split_len);
@@ -111,8 +119,8 @@ fn split_visible_macro_spans(covspans: &mut Vec) {
return true;
}
- extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb));
- extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb));
+ extra_spans.push(SpanFromMir::new(before, covspan.expn_kind.clone(), covspan.bcb));
+ extra_spans.push(SpanFromMir::new(after, covspan.expn_kind.clone(), covspan.bcb));
false // Discard the original covspan that we just split.
});
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 32bd25bf4b966..7f5765c9462de 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -3,13 +3,13 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::{
self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind,
};
-use rustc_span::{Span, Symbol};
+use rustc_span::{ExpnKind, Span};
use crate::coverage::graph::{
BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB,
};
use crate::coverage::spans::Covspan;
-use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro;
+use crate::coverage::unexpand::unexpand_into_body_span_with_expn_kind;
use crate::coverage::ExtractedHirInfo;
pub(crate) struct ExtractedCovspans {
@@ -60,7 +60,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
let data = &mir_body[bb];
let unexpand = move |expn_span| {
- unexpand_into_body_span_with_visible_macro(expn_span, body_span)
+ unexpand_into_body_span_with_expn_kind(expn_span, body_span)
// Discard any spans that fill the entire body, because they tend
// to represent compiler-inserted code, e.g. implicitly returning `()`.
.filter(|(span, _)| !span.source_equal(body_span))
@@ -68,9 +68,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
let mut extract_statement_span = |statement| {
let expn_span = filtered_statement_span(statement)?;
- let (span, visible_macro) = unexpand(expn_span)?;
+ let (span, expn_kind) = unexpand(expn_span)?;
- initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb));
+ initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb));
Some(())
};
for statement in data.statements.iter() {
@@ -79,9 +79,9 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>(
let mut extract_terminator_span = |terminator| {
let expn_span = filtered_terminator_span(terminator)?;
- let (span, visible_macro) = unexpand(expn_span)?;
+ let (span, expn_kind) = unexpand(expn_span)?;
- initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb));
+ initial_covspans.push(SpanFromMir::new(span, expn_kind, bcb));
Some(())
};
extract_terminator_span(data.terminator());
@@ -214,7 +214,7 @@ pub(crate) struct SpanFromMir {
/// With the exception of `fn_sig_span`, this should always be contained
/// within `body_span`.
pub(crate) span: Span,
- pub(crate) visible_macro: Option,
+ pub(crate) expn_kind: Option,
pub(crate) bcb: BasicCoverageBlock,
}
@@ -223,12 +223,12 @@ impl SpanFromMir {
Self::new(fn_sig_span, None, START_BCB)
}
- pub(crate) fn new(span: Span, visible_macro: Option, bcb: BasicCoverageBlock) -> Self {
- Self { span, visible_macro, bcb }
+ pub(crate) fn new(span: Span, expn_kind: Option, bcb: BasicCoverageBlock) -> Self {
+ Self { span, expn_kind, bcb }
}
pub(crate) fn into_covspan(self) -> Covspan {
- let Self { span, visible_macro: _, bcb } = self;
+ let Self { span, expn_kind: _, bcb } = self;
Covspan { span, bcb }
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs
index 8cde291b9073e..cb8615447362b 100644
--- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs
+++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs
@@ -1,4 +1,4 @@
-use rustc_span::{ExpnKind, MacroKind, Span, Symbol};
+use rustc_span::{ExpnKind, Span};
/// Walks through the expansion ancestors of `original_span` to find a span that
/// is contained in `body_span` and has the same [syntax context] as `body_span`.
@@ -13,20 +13,15 @@ pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> O
///
/// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`),
/// the returned symbol will be the name of that macro (e.g. `foo`).
-pub(crate) fn unexpand_into_body_span_with_visible_macro(
+pub(crate) fn unexpand_into_body_span_with_expn_kind(
original_span: Span,
body_span: Span,
-) -> Option<(Span, Option)> {
+) -> Option<(Span, Option)> {
let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?;
- let visible_macro = prev
- .map(|prev| match prev.ctxt().outer_expn_data().kind {
- ExpnKind::Macro(MacroKind::Bang, name) => Some(name),
- _ => None,
- })
- .flatten();
+ let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind);
- Some((span, visible_macro))
+ Some((span, expn_kind))
}
/// Walks through the expansion ancestors of `original_span` to find a span that
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index bf522fd5ef4ec..ea473b64ce540 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -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();
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index b16d25c93bb96..46f7408ef8064 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -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
}
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 39c8db184a5a2..9081a2e2e3028 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -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",
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index b38f4a4a823b1..be50c1da8a438 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -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
}
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 0e2fccc85dacd..a878f777448f5 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -78,7 +78,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
checker.patcher.apply(body);
}
-impl<'tcx> MirPass<'tcx> for Derefer {
+impl<'tcx> crate::MirPass<'tcx> for Derefer {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
deref_finder(tcx, body);
}
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index a6d626d3f8ff5..67bee36b8a5e2 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -146,11 +146,9 @@ use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex
use rustc_mir_dataflow::Analysis;
use tracing::{debug, trace};
-use crate::MirPass;
-
pub struct DestinationPropagation;
-impl<'tcx> MirPass<'tcx> for DestinationPropagation {
+impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// For now, only run at MIR opt level 3. Two things need to be changed before this can be
// turned on by default:
@@ -165,7 +163,8 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
- let mut allocations = Allocations::default();
+ let mut candidates = Candidates::default();
+ let mut write_info = WriteInfo::default();
trace!(func = ?tcx.def_path_str(def_id));
let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
@@ -193,12 +192,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
loop {
// PERF: Can we do something smarter than recalculating the candidates and liveness
// results?
- let mut candidates = find_candidates(
- body,
- &borrowed,
- &mut allocations.candidates,
- &mut allocations.candidates_reverse,
- );
+ candidates.reset_and_find(body, &borrowed);
trace!(?candidates);
dest_prop_mir_dump(tcx, body, &points, &live, round_count);
@@ -206,7 +200,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
&mut candidates,
&points,
&live,
- &mut allocations.write_info,
+ &mut write_info,
body,
);
@@ -255,20 +249,8 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation {
}
}
-/// Container for the various allocations that we need.
-///
-/// We store these here and hand out `&mut` access to them, instead of dropping and recreating them
-/// frequently. Everything with a `&'alloc` lifetime points into here.
-#[derive(Default)]
-struct Allocations {
- candidates: FxIndexMap>,
- candidates_reverse: FxIndexMap>,
- write_info: WriteInfo,
- // PERF: Do this for `MaybeLiveLocals` allocations too.
-}
-
-#[derive(Debug)]
-struct Candidates<'alloc> {
+#[derive(Debug, Default)]
+struct Candidates {
/// The set of candidates we are considering in this optimization.
///
/// We will always merge the key into at most one of its values.
@@ -283,11 +265,12 @@ struct Candidates<'alloc> {
///
/// We will still report that we would like to merge `_1` and `_2` in an attempt to allow us to
/// remove that assignment.
- c: &'alloc mut FxIndexMap>,
+ c: FxIndexMap>,
+
/// A reverse index of the `c` set; if the `c` set contains `a => Place { local: b, proj }`,
/// then this contains `b => a`.
// PERF: Possibly these should be `SmallVec`s?
- reverse: &'alloc mut FxIndexMap>,
+ reverse: FxIndexMap>,
}
//////////////////////////////////////////////////////////
@@ -360,19 +343,40 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Merger<'a, 'tcx> {
//
// This section enforces bullet point 2
-struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
- body: &'body Body<'tcx>,
+struct FilterInformation<'a, 'tcx> {
+ body: &'a Body<'tcx>,
points: &'a DenseLocationMap,
live: &'a SparseIntervalMatrix,
- candidates: &'a mut Candidates<'alloc>,
- write_info: &'alloc mut WriteInfo,
+ candidates: &'a mut Candidates,
+ write_info: &'a mut WriteInfo,
at: Location,
}
// We first implement some utility functions which we will expose removing candidates according to
// different needs. Throughout the liveness filtering, the `candidates` are only ever accessed
// through these methods, and not directly.
-impl<'alloc> Candidates<'alloc> {
+impl Candidates {
+ /// Collects the candidates for merging.
+ ///
+ /// This is responsible for enforcing the first and third bullet point.
+ fn reset_and_find<'tcx>(&mut self, body: &Body<'tcx>, borrowed: &BitSet) {
+ self.c.clear();
+ self.reverse.clear();
+ let mut visitor = FindAssignments { body, candidates: &mut self.c, borrowed };
+ visitor.visit_body(body);
+ // Deduplicate candidates.
+ for (_, cands) in self.c.iter_mut() {
+ cands.sort();
+ cands.dedup();
+ }
+ // Generate the reverse map.
+ for (src, cands) in self.c.iter() {
+ for dest in cands.iter().copied() {
+ self.reverse.entry(dest).or_default().push(*src);
+ }
+ }
+ }
+
/// Just `Vec::retain`, but the condition is inverted and we add debugging output
fn vec_filter_candidates(
src: Local,
@@ -447,7 +451,7 @@ enum CandidateFilter {
Remove,
}
-impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
+impl<'a, 'tcx> FilterInformation<'a, 'tcx> {
/// Filters the set of candidates to remove those that conflict.
///
/// The steps we take are exactly those that are outlined at the top of the file. For each
@@ -465,12 +469,12 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
/// before the statement/terminator will correctly report locals that are read in the
/// statement/terminator to be live. We are additionally conservative by treating all written to
/// locals as also being read from.
- fn filter_liveness<'b>(
- candidates: &mut Candidates<'alloc>,
+ fn filter_liveness(
+ candidates: &mut Candidates,
points: &DenseLocationMap,
live: &SparseIntervalMatrix,
- write_info_alloc: &'alloc mut WriteInfo,
- body: &'b Body<'tcx>,
+ write_info: &mut WriteInfo,
+ body: &Body<'tcx>,
) {
let mut this = FilterInformation {
body,
@@ -479,7 +483,7 @@ impl<'a, 'body, 'alloc, 'tcx> FilterInformation<'a, 'body, 'alloc, 'tcx> {
candidates,
// We don't actually store anything at this scope, we just keep things here to be able
// to reuse the allocation.
- write_info: write_info_alloc,
+ write_info,
// Doesn't matter what we put here, will be overwritten before being used
at: Location::START,
};
@@ -736,40 +740,13 @@ fn places_to_candidate_pair<'tcx>(
Some((a, b))
}
-/// Collects the candidates for merging
-///
-/// This is responsible for enforcing the first and third bullet point.
-fn find_candidates<'alloc, 'tcx>(
- body: &Body<'tcx>,
- borrowed: &BitSet,
- candidates: &'alloc mut FxIndexMap>,
- candidates_reverse: &'alloc mut FxIndexMap>,
-) -> Candidates<'alloc> {
- candidates.clear();
- candidates_reverse.clear();
- let mut visitor = FindAssignments { body, candidates, borrowed };
- visitor.visit_body(body);
- // Deduplicate candidates
- for (_, cands) in candidates.iter_mut() {
- cands.sort();
- cands.dedup();
- }
- // Generate the reverse map
- for (src, cands) in candidates.iter() {
- for dest in cands.iter().copied() {
- candidates_reverse.entry(dest).or_default().push(*src);
- }
- }
- Candidates { c: candidates, reverse: candidates_reverse }
-}
-
-struct FindAssignments<'a, 'alloc, 'tcx> {
+struct FindAssignments<'a, 'tcx> {
body: &'a Body<'tcx>,
- candidates: &'alloc mut FxIndexMap>,
+ candidates: &'a mut FxIndexMap>,
borrowed: &'a BitSet,
}
-impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
+impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
if let StatementKind::Assign(box (
lhs,
@@ -821,9 +798,9 @@ fn is_local_required(local: Local, body: &Body<'_>) -> bool {
/////////////////////////////////////////////////////////
// MIR Dump
-fn dest_prop_mir_dump<'body, 'tcx>(
+fn dest_prop_mir_dump<'tcx>(
tcx: TyCtxt<'tcx>,
- body: &'body Body<'tcx>,
+ body: &Body<'tcx>,
points: &DenseLocationMap,
live: &SparseIntervalMatrix,
round: usize,
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 29db45f94506f..06ae1b490d75c 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -7,11 +7,9 @@ use rustc_middle::mir::{write_mir_pretty, Body};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutFileName, OutputType};
-use crate::MirPass;
-
pub struct Marker(pub &'static str);
-impl<'tcx> MirPass<'tcx> for Marker {
+impl<'tcx> crate::MirPass<'tcx> for Marker {
fn name(&self) -> &'static str {
self.0
}
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 67b81efd61475..1c54cd70023d6 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -92,7 +92,7 @@ use super::simplify::simplify_cfg;
/// ```
pub struct EarlyOtherwiseBranch;
-impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
+impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index e5778f8a05d2e..66e49d556e23c 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -62,11 +62,13 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
let base_ty = self.local_decls[place.local].ty;
// Derefer ensures that derefs are always the first projection
- if place.projection.first() == Some(&PlaceElem::Deref) && base_ty.is_box() {
+ if let Some(PlaceElem::Deref) = place.projection.first()
+ && let Some(boxed_ty) = base_ty.boxed_ty()
+ {
let source_info = self.local_decls[place.local].source_info;
let (unique_ty, nonnull_ty, ptr_ty) =
- build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did);
+ build_ptr_tys(tcx, boxed_ty, self.unique_did, self.nonnull_did);
let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
@@ -88,7 +90,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
pub struct ElaborateBoxDerefs;
-impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if let Some(def_id) = tcx.lang_items().owned_box() {
let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
@@ -120,13 +122,15 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
for (base, elem) in place.iter_projections() {
let base_ty = base.ty(&body.local_decls, tcx).ty;
- if elem == PlaceElem::Deref && base_ty.is_box() {
+ if let PlaceElem::Deref = elem
+ && let Some(boxed_ty) = base_ty.boxed_ty()
+ {
// Clone the projections before us, since now we need to mutate them.
let new_projections =
new_projections.get_or_insert_with(|| base.projection.to_vec());
let (unique_ty, nonnull_ty, ptr_ty) =
- build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did);
+ build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did);
new_projections.extend_from_slice(&build_projection(
unique_ty, nonnull_ty, ptr_ty,
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index d0809d9388def..f4a951ebde600 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -49,7 +49,7 @@ use crate::deref_separator::deref_finder;
/// ```
pub struct ElaborateDrops;
-impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
#[instrument(level = "trace", skip(self, tcx, body))]
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index b7873e73c18c7..199fd0f10ee2c 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -9,11 +9,11 @@ use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
-use crate::{errors, MirLint};
+use crate::errors;
pub struct FunctionItemReferences;
-impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+impl<'tcx> crate::MirLint<'tcx> for FunctionItemReferences {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let mut checker = FunctionItemRefChecker { tcx, body };
checker.visit_body(body);
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index fb9baeeb3ed88..df0fcc42e5926 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -111,7 +111,7 @@ use crate::ssa::{AssignedValue, SsaLocals};
pub struct GVN;
-impl<'tcx> MirPass<'tcx> for GVN {
+impl<'tcx> crate::MirPass<'tcx> for GVN {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 4482801826ab0..6cc7e0ee1e4bc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -42,7 +42,7 @@ struct CallSite<'tcx> {
source_info: SourceInfo,
}
-impl<'tcx> MirPass<'tcx> for Inline {
+impl<'tcx> crate::MirPass<'tcx> for Inline {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
// MIR correctly when Modified Condition/Decision Coverage is enabled.
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 3ec553d0ba0c5..4fbfa744e6733 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -27,7 +27,7 @@ impl InstSimplify {
}
}
-impl<'tcx> MirPass<'tcx> for InstSimplify {
+impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
fn name(&self) -> &'static str {
self.name()
}
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 435b6a0116348..02dd56e1b4fdb 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -61,7 +61,7 @@ const MAX_BACKTRACK: usize = 5;
const MAX_COST: usize = 100;
const MAX_PLACES: usize = 100;
-impl<'tcx> MirPass<'tcx> for JumpThreading {
+impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 15d71ee2ac81f..61405fb25c6f2 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -25,11 +25,10 @@ use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, Va
use tracing::{debug, instrument, trace};
use crate::errors::{AssertLint, AssertLintKind};
-use crate::MirLint;
pub struct KnownPanicsLint;
-impl<'tcx> MirLint<'tcx> for KnownPanicsLint {
+impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
if body.tainted_by_errors.is_some() {
return;
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index cbc3169f2f10a..f02ba71ddc64c 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -27,7 +27,7 @@ pub struct EnumSizeOpt {
pub(crate) discrepancy: u64,
}
-impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
+impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
fn is_enabled(&self, sess: &Session) -> bool {
// There are some differences in behavior on wasm and ARM that are not properly
// understood, so we conservatively treat this optimization as unsound:
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9e460a725eeb2..62e73ba2c8e24 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -26,13 +26,12 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_index::IndexVec;
use rustc_middle::mir::{
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
- MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
+ MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
Statement, StatementKind, TerminatorKind, START_BLOCK,
};
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_middle::util::Providers;
use rustc_middle::{bug, query, span_bug};
-use rustc_mir_dataflow::rustc_peek;
use rustc_span::source_map::Spanned;
use rustc_span::{sym, DUMMY_SP};
use rustc_trait_selection::traits;
@@ -41,7 +40,7 @@ use tracing::{debug, trace};
#[macro_use]
mod pass_manager;
-use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
mod abort_unwinding_calls;
mod add_call_guards;
@@ -96,6 +95,7 @@ mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
mod reveal_all;
+mod sanity_check;
mod shim;
mod ssa;
// This pass is public to allow external drivers to perform MIR cleanup
@@ -288,7 +288,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> {
&Lint(function_item_references::FunctionItemReferences),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::Initial,
- &rustc_peek::SanityCheck, // Just a lint
+ &Lint(sanity_check::SanityCheck),
],
None,
);
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index a9bdff95fe5ac..55eec33230615 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -9,7 +9,7 @@ use crate::take_array;
pub struct LowerIntrinsics;
-impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
+impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let local_decls = &body.local_decls;
for block in body.basic_blocks.as_mut() {
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 77a7f4f47dd4e..555309a775001 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
pub struct LowerSliceLenCalls;
-impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 5240f1c887c5c..233b39fb47a41 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
pub struct MatchBranchSimplification;
-impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 1
}
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index 32c8064ebca50..41ce03caf0873 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -1,5 +1,5 @@
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
+use rustc_middle::mir::{self, Location, MentionedItem};
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
@@ -13,7 +13,7 @@ struct MentionedItemsVisitor<'a, 'tcx> {
mentioned_items: &'a mut Vec>>,
}
-impl<'tcx> MirPass<'tcx> for MentionedItems {
+impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
fn is_enabled(&self, _sess: &Session) -> bool {
// If this pass is skipped the collector assume that nothing got mentioned! We could
// potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index 1e87a0e01d9be..1b4972d487eea 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -9,7 +9,7 @@ use crate::simplify;
pub struct MultipleReturnTerminators;
-impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
+impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 4
}
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index dd1875f2a78ac..94573a9d89bfd 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -8,8 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
use rustc_middle::ty::TyCtxt;
use tracing::{debug, trace};
-use crate::MirPass;
-
/// This pass looks for MIR that always copies the same local into the return place and eliminates
/// the copy by renaming all uses of that local to `_0`.
///
@@ -34,7 +32,7 @@ use crate::MirPass;
/// [#71003]: https://github.com/rust-lang/rust/pull/71003
pub struct RenameReturnPlace;
-impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
+impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// unsound: #111005
sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 51e2760040478..28d4e1a1c9184 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -1,19 +1,99 @@
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use tracing::trace;
use crate::lint::lint_body;
-use crate::{validate, MirPass};
+use crate::validate;
+
+thread_local! {
+ static PASS_NAMES: RefCell> = {
+ 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
+ }
+ })
+}
+
+// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
+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,
+ }
+}
+
+/// 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(super) 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::();
+ 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
+ }
+}
-/// Just like `MirPass`, except it cannot mutate `Body`.
-pub trait MirLint<'tcx> {
+/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
+/// disabled (via the `Lint` adapter).
+pub(super) trait MirLint<'tcx> {
fn name(&self) -> &'static str {
// FIXME Simplify the implementation once more `str` methods get const-stable.
// See copypaste in `MirPass`
const {
let name = std::any::type_name::();
- rustc_middle::util::common::c_name(name)
+ c_name(name)
}
}
@@ -26,7 +106,7 @@ pub trait MirLint<'tcx> {
/// An adapter for `MirLint`s that implements `MirPass`.
#[derive(Debug, Clone)]
-pub struct Lint(pub T);
+pub(super) struct Lint(pub T);
impl<'tcx, T> MirPass<'tcx> for Lint
where
@@ -49,7 +129,7 @@ where
}
}
-pub struct WithMinOptLevel(pub u32, pub T);
+pub(super) struct WithMinOptLevel(pub u32, pub T);
impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel
where
@@ -70,7 +150,7 @@ where
/// Run the sequence of passes without validating the MIR after each pass. The MIR is still
/// validated at the end.
-pub fn run_passes_no_validate<'tcx>(
+pub(super) fn run_passes_no_validate<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
@@ -80,7 +160,7 @@ pub fn run_passes_no_validate<'tcx>(
}
/// The optional `phase_change` is applied after executing all the passes, if present
-pub fn run_passes<'tcx>(
+pub(super) fn run_passes<'tcx>(
tcx: TyCtxt<'tcx>,
body: &mut Body<'tcx>,
passes: &[&dyn MirPass<'tcx>],
@@ -89,7 +169,7 @@ pub fn run_passes<'tcx>(
run_passes_inner(tcx, body, passes, phase_change, true);
}
-pub fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
+pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
where
P: MirPass<'tcx> + ?Sized,
{
@@ -185,11 +265,11 @@ fn run_passes_inner<'tcx>(
}
}
-pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
}
-pub fn dump_mir_for_pass<'tcx>(
+pub(super) fn dump_mir_for_pass<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
pass_name: &str,
@@ -205,7 +285,7 @@ pub fn dump_mir_for_pass<'tcx>(
);
}
-pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
assert_eq!(body.pass_count, 0);
mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(()))
}
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 14dd0c6f61e76..ad71c6226601c 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -17,7 +17,7 @@ use rustc_session::Session;
/// `IndexVec`, unless that successor is a back-edge (such as from a loop).
pub struct ReorderBasicBlocks;
-impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
+impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
fn is_enabled(&self, _session: &Session) -> bool {
false
}
@@ -45,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
/// (Does not reorder arguments nor the [`RETURN_PLACE`].)
pub struct ReorderLocals;
-impl<'tcx> MirPass<'tcx> for ReorderLocals {
+impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
fn is_enabled(&self, _session: &Session) -> bool {
false
}
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 0c940bac13c0b..cf0a569ffa494 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
pub promoted_fragments: Cell>>,
}
-impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// There's not really any point in promoting errorful MIR.
//
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 8d0b47cb34a8f..4a447d24ccec7 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -72,7 +72,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
/// so we perform all the possible instantiations without removing the `_1 = &_2` statement.
pub struct ReferencePropagation;
-impl<'tcx> MirPass<'tcx> for ReferencePropagation {
+impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 33c7d1695c02d..ccba8d015e3a6 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -10,7 +10,7 @@ use tracing::debug;
/// terrible code for these.
pub struct RemoveNoopLandingPads;
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.panic_strategy() != PanicStrategy::Abort
}
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index 6c0b50fafdb40..5801fdedcebb2 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -6,7 +6,7 @@ use tracing::trace;
pub struct RemovePlaceMention;
-impl<'tcx> MirPass<'tcx> for RemovePlaceMention {
+impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
!sess.opts.unstable_opts.mir_keep_place_mention
}
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index af89395dddd2d..329b30d3890a3 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -6,7 +6,7 @@ use tracing::trace;
pub struct RemoveStorageMarkers;
-impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers()
}
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index fae1cb5f7d8a5..aafe971311d31 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -6,8 +6,6 @@ use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
use rustc_target::abi::FieldIdx;
-use crate::MirPass;
-
/// Removes `Drop` terminators whose target is known to be uninitialized at
/// that point.
///
@@ -18,7 +16,7 @@ use crate::MirPass;
/// [#90770]: https://github.com/rust-lang/rust/issues/90770
pub struct RemoveUninitDrops;
-impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env(body.source.def_id());
let move_data =
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 9adcb5a38fd8b..43109aae0fb6c 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
pub struct RemoveUnneededDrops;
-impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("Running RemoveUnneededDrops on {:?}", body.source);
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 9a94cae338288..9aa46bd4fbae6 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RemoveZsts;
-impl<'tcx> MirPass<'tcx> for RemoveZsts {
+impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 5eaa024f84689..29312a99cbc01 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
pub struct RevealAll;
-impl<'tcx> MirPass<'tcx> for RevealAll {
+impl<'tcx> crate::MirPass<'tcx> for RevealAll {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
diff --git a/compiler/rustc_mir_transform/src/sanity_check.rs b/compiler/rustc_mir_transform/src/sanity_check.rs
new file mode 100644
index 0000000000000..c9445d1816295
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/sanity_check.rs
@@ -0,0 +1,11 @@
+use rustc_middle::mir::Body;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::rustc_peek::sanity_check;
+
+pub(super) struct SanityCheck;
+
+impl<'tcx> crate::MirLint<'tcx> for SanityCheck {
+ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+ sanity_check(tcx, body);
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d1c2c91e00fd7..1478b86d3c765 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -74,7 +74,7 @@ pub(crate) fn simplify_cfg(body: &mut Body<'_>) {
body.basic_blocks_mut().raw.shrink_to_fit();
}
-impl<'tcx> MirPass<'tcx> for SimplifyCfg {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
fn name(&self) -> &'static str {
self.name()
}
@@ -366,7 +366,7 @@ pub enum SimplifyLocals {
Final,
}
-impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
fn name(&self) -> &'static str {
match &self {
SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 7c8a686d0077e..5a014bb734683 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -7,7 +7,7 @@ pub enum SimplifyConstCondition {
Final,
}
/// A pass that replaces a branch with a goto when its condition is known.
-impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
fn name(&self) -> &'static str {
match self {
SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index ac892adebec1b..bd30ecc59b3d7 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -9,8 +9,6 @@ use rustc_middle::mir::{
use rustc_middle::ty::{Ty, TyCtxt};
use tracing::trace;
-use super::MirPass;
-
/// Pass to convert `if` conditions on integrals into switches on the integral.
/// For an example, it turns something like
///
@@ -27,7 +25,7 @@ use super::MirPass;
/// ```
pub struct SimplifyComparisonIntegral;
-impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 35cb6872fe9a2..64a928728307b 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::TyCtxt;
/// needed to do that too, including updating the debug info.
pub struct SingleUseConsts;
-impl<'tcx> MirPass<'tcx> for SingleUseConsts {
+impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 906e2c23f3b8c..3c5ccc0c99a8a 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -13,7 +13,7 @@ use tracing::{debug, instrument};
pub struct ScalarReplacementOfAggregates;
-impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
+impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() >= 2
}
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 2427fbac5eefa..51a322628ee69 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -12,8 +12,6 @@ use rustc_middle::ty::{Ty, TyCtxt};
use rustc_target::abi::{Abi, Variants};
use tracing::trace;
-use crate::MirPass;
-
pub struct UnreachableEnumBranching;
fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option {
@@ -74,7 +72,7 @@ fn variant_discriminants<'tcx>(
}
}
-impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
+impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index a6c3c3b189ed0..b8da86f1a8dde 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -12,7 +12,7 @@ use rustc_target::abi::Size;
pub struct UnreachablePropagation;
-impl MirPass<'_> for UnreachablePropagation {
+impl crate::MirPass<'_> for UnreachablePropagation {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
// Enable only under -Zmir-opt-level=2 as this can make programs less debuggable.
sess.mir_opt_level() >= 2
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 99e06f59dd04d..69e2592e82c77 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -36,7 +36,7 @@ pub struct Validator {
pub mir_phase: MirPhase,
}
-impl<'tcx> MirPass<'tcx> for Validator {
+impl<'tcx> crate::MirPass<'tcx> for Validator {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
// terribly important that they pass the validator. However, I think other passes might
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 8515ab45de217..093697a290c00 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1041,8 +1041,11 @@ fn find_vtable_types_for_unsizing<'tcx>(
match (source_ty.kind(), target_ty.kind()) {
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
- (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
- ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
+ (_, _)
+ if let Some(source_boxed) = source_ty.boxed_ty()
+ && let Some(target_boxed) = target_ty.boxed_ty() =>
+ {
+ ptr_vtable(source_boxed, target_boxed)
}
// T as dyn* Trait
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index b22e8e30465ea..91101ddd59022 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,5 +1,7 @@
// tidy-alphabetical-start
#![feature(array_windows)]
+#![feature(if_let_guard)]
+#![feature(let_chains)]
#![warn(unreachable_pub)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index bb05eb4c25697..6c9a6011144cd 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -304,6 +304,11 @@ where
let mut candidates = vec![];
+ if self.solver_mode() == SolverMode::Coherence {
+ if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
+ return vec![candidate];
+ }
+ }
self.assemble_impl_candidates(goal, &mut candidates);
self.assemble_builtin_impl_candidates(goal, &mut candidates);
@@ -314,11 +319,8 @@ where
self.assemble_param_env_candidates(goal, &mut candidates);
- match self.solver_mode() {
- SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
- SolverMode::Coherence => {
- self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
- }
+ if self.solver_mode() == SolverMode::Normal {
+ self.discard_impls_shadowed_by_env(goal, &mut candidates);
}
candidates
@@ -682,38 +684,34 @@ where
/// also consider impls which may get added in a downstream or sibling crate
/// or which an upstream impl may add in a minor release.
///
- /// To do so we add an ambiguous candidate in case such an unknown impl could
- /// apply to the current goal.
+ /// To do so we return a single ambiguous candidate in case such an unknown
+ /// impl could apply to the current goal.
#[instrument(level = "trace", skip_all)]
- fn assemble_coherence_unknowable_candidates>(
+ fn consider_coherence_unknowable_candidate>(
&mut self,
goal: Goal,
- candidates: &mut Vec>,
- ) {
- let cx = self.cx();
-
- candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
- |ecx| {
- let trait_ref = goal.predicate.trait_ref(cx);
- if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
- Err(NoSolution)
- } else {
- // While the trait bound itself may be unknowable, we may be able to
- // prove that a super trait is not implemented. For this, we recursively
- // prove the super trait bounds of the current goal.
- //
- // We skip the goal itself as that one would cycle.
- let predicate: I::Predicate = trait_ref.upcast(cx);
- ecx.add_goals(
- GoalSource::Misc,
- elaborate::elaborate(cx, [predicate])
- .skip(1)
- .map(|predicate| goal.with(cx, predicate)),
- );
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
- }
- },
- ))
+ ) -> Result, NoSolution> {
+ self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
+ let cx = ecx.cx();
+ let trait_ref = goal.predicate.trait_ref(cx);
+ if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
+ Err(NoSolution)
+ } else {
+ // While the trait bound itself may be unknowable, we may be able to
+ // prove that a super trait is not implemented. For this, we recursively
+ // prove the super trait bounds of the current goal.
+ //
+ // We skip the goal itself as that one would cycle.
+ let predicate: I::Predicate = trait_ref.upcast(cx);
+ ecx.add_goals(
+ GoalSource::Misc,
+ elaborate::elaborate(cx, [predicate])
+ .skip(1)
+ .map(|predicate| goal.with(cx, predicate)),
+ );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+ }
+ })
}
/// If there's a where-bound for the current goal, do not use any impl candidates
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index c7a9846cd97f0..17b6ec7e2bb2c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -3,7 +3,7 @@ mod inherent;
mod opaque_types;
mod weak_types;
-use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
@@ -106,6 +106,12 @@ where
if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.projection_def_id() == goal.predicate.def_id() {
let cx = ecx.cx();
+ if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
+ goal.predicate.alias.args,
+ projection_pred.skip_binder().projection_term.args,
+ ) {
+ return Err(NoSolution);
+ }
ecx.probe_trait_candidate(source).enter(|ecx| {
let assumption_projection_pred =
ecx.instantiate_binder_with_infer(projection_pred);
@@ -144,7 +150,7 @@ where
let goal_trait_ref = goal.predicate.alias.trait_ref(cx);
let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
- if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup).args_may_unify(
+ if !DeepRejectCtxt::relate_rigid_infer(ecx.cx()).args_may_unify(
goal.predicate.alias.trait_ref(cx).args,
impl_trait_ref.skip_binder().args,
) {
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 67b001d0cceda..683d8dab3b2a8 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -2,7 +2,7 @@
use rustc_ast_ir::Movability;
use rustc_type_ir::data_structures::IndexSet;
-use rustc_type_ir::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_type_ir::fast_reject::DeepRejectCtxt;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::visit::TypeVisitableExt as _;
@@ -47,7 +47,7 @@ where
let cx = ecx.cx();
let impl_trait_ref = cx.impl_trait_ref(impl_def_id);
- if !DeepRejectCtxt::new(ecx.cx(), TreatParams::ForLookup)
+ if !DeepRejectCtxt::relate_rigid_infer(ecx.cx())
.args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
{
return Err(NoSolution);
@@ -124,6 +124,13 @@ where
if trait_clause.def_id() == goal.predicate.def_id()
&& trait_clause.polarity() == goal.predicate.polarity
{
+ if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
+ goal.predicate.trait_ref.args,
+ trait_clause.skip_binder().trait_ref.args,
+ ) {
+ return Err(NoSolution);
+ }
+
ecx.probe_trait_candidate(source).enter(|ecx| {
let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
ecx.eq(
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 21478a44b0e14..e41f89a3c9da9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -125,7 +125,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
[sym::coverage, ..] => self.check_coverage(attr, span, target),
[sym::optimize, ..] => self.check_optimize(hir_id, attr, target),
- [sym::no_sanitize, ..] => self.check_no_sanitize(hir_id, attr, span, target),
+ [sym::no_sanitize, ..] => {
+ self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+ }
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
[sym::target_feature, ..] => {
@@ -166,10 +168,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
}
[sym::rustc_lint_query_instability, ..] => {
- self.check_rustc_lint_query_instability(hir_id, attr, span, target)
+ self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+ }
+ [sym::rustc_lint_untracked_query_information, ..] => {
+ self.check_applied_to_fn_or_method(hir_id, attr, span, target)
}
[sym::rustc_lint_diagnostics, ..] => {
- self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
+ self.check_applied_to_fn_or_method(hir_id, attr, span, target)
}
[sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
[sym::rustc_lint_opt_deny_field_access, ..] => {
@@ -452,11 +457,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
- /// Checks that `#[no_sanitize(..)]` is applied to a function or method.
- fn check_no_sanitize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
- self.check_applied_to_fn_or_method(hir_id, attr, span, target)
- }
-
fn check_generic_attr(
&self,
hir_id: HirId,
@@ -1635,30 +1635,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
- /// Checks that the `#[rustc_lint_query_instability]` attribute is only applied to a function
- /// or method.
- fn check_rustc_lint_query_instability(
- &self,
- hir_id: HirId,
- attr: &Attribute,
- span: Span,
- target: Target,
- ) {
- self.check_applied_to_fn_or_method(hir_id, attr, span, target)
- }
-
- /// Checks that the `#[rustc_lint_diagnostics]` attribute is only applied to a function or
- /// method.
- fn check_rustc_lint_diagnostics(
- &self,
- hir_id: HirId,
- attr: &Attribute,
- span: Span,
- target: Target,
- ) {
- self.check_applied_to_fn_or_method(hir_id, attr, span, target)
- }
-
/// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
match target {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 25115c5cafd89..c11562ae39e3c 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -19,17 +19,25 @@ use crate::errors::{
OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};
+/// The context in which a block is encountered.
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
Fn,
Loop(hir::LoopSource),
Closure(Span),
- Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
+ Coroutine {
+ coroutine_span: Span,
+ kind: hir::CoroutineDesugaring,
+ source: hir::CoroutineSource,
+ },
UnlabeledBlock(Span),
UnlabeledIfBlock(Span),
LabeledBlock,
- Constant,
+ /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`.
+ AnonConst,
+ /// E.g. `const { ... }`.
+ ConstBlock,
}
#[derive(Clone)]
@@ -90,11 +98,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
- self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
+ self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
}
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
- self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
+ self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c));
}
fn visit_fn(
@@ -128,7 +136,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
&& matches!(
ck_loop.cx_stack.last(),
Some(&Normal)
- | Some(&Constant)
+ | Some(&AnonConst)
| Some(&UnlabeledBlock(_))
| Some(&UnlabeledIfBlock(_))
)
@@ -175,14 +183,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprKind::Block(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(b));
}
- hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => {
+ hir::ExprKind::Block(ref b, None)
+ if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) =>
+ {
self.with_context(Normal, |v| v.visit_block(b));
}
- hir::ExprKind::Block(ref b, None)
- if matches!(
- self.cx_stack.last(),
- Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_))
- ) =>
+ hir::ExprKind::Block(
+ ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. },
+ None,
+ ) if matches!(
+ self.cx_stack.last(),
+ Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_))
+ ) =>
{
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
}
@@ -353,7 +365,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
}
- Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => {
+ Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
self.sess.dcx().emit_err(OutsideLoop {
spans: vec![span],
name: &br_cx_kind.to_string(),
@@ -365,7 +377,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
}
fn require_label_in_labeled_block(
- &mut self,
+ &self,
span: Span,
label: &Destination,
cf_type: &str,
@@ -380,7 +392,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
false
}
- fn report_outside_loop_error(&mut self) {
+ fn report_outside_loop_error(&self) {
for (s, block) in &self.block_breaks {
self.sess.dcx().emit_err(OutsideLoop {
spans: block.spans.clone(),
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d7885e05a2ffc..6c09f97bfe731 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
} else {
let variant =
&adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
-
- // In the cases of either a `#[non_exhaustive]` field list or a non-public
- // field, we skip uninhabited fields in order not to reveal the
- // uninhabitedness of the whole variant.
- let is_non_exhaustive =
- variant.is_field_list_non_exhaustive() && !adt.did().is_local();
let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
let is_visible =
adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
let is_uninhabited = cx.is_uninhabited(*ty);
- let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
+ let skip = is_uninhabited && !is_visible;
(ty, PrivateUninhabitedField(skip))
});
cx.dropless_arena.alloc_from_iter(tys)
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 908d50a041ef1..f3e3b36111c54 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -842,6 +842,11 @@ pub struct NextSolverConfig {
/// This is only `true` if `coherence` is also enabled.
pub globally: bool,
}
+impl Default for NextSolverConfig {
+ fn default() -> Self {
+ NextSolverConfig { coherence: true, globally: false }
+ }
+}
#[derive(Clone)]
pub enum Input {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 45339c23ea3ef..a57dc80b3168d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -403,7 +403,7 @@ mod desc {
pub(crate) const parse_unpretty: &str = "`string` or `string=string`";
pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
pub(crate) const parse_next_solver_config: &str =
- "a comma separated list of solver configurations: `globally` (default), and `coherence`";
+ "either `globally` (when used without an argument), `coherence` (default) or `no`";
pub(crate) const parse_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub(crate) const parse_linker_plugin_lto: &str =
@@ -1105,27 +1105,16 @@ mod parse {
}
}
- pub(crate) fn parse_next_solver_config(
- slot: &mut Option,
- v: Option<&str>,
- ) -> bool {
+ pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool {
if let Some(config) = v {
- let mut coherence = false;
- let mut globally = true;
- for c in config.split(',') {
- match c {
- "globally" => globally = true,
- "coherence" => {
- globally = false;
- coherence = true;
- }
- _ => return false,
- }
- }
-
- *slot = Some(NextSolverConfig { coherence: coherence || globally, globally });
+ *slot = match config {
+ "no" => NextSolverConfig { coherence: false, globally: false },
+ "coherence" => NextSolverConfig { coherence: true, globally: false },
+ "globally" => NextSolverConfig { coherence: true, globally: true },
+ _ => return false,
+ };
} else {
- *slot = Some(NextSolverConfig { coherence: true, globally: true });
+ *slot = NextSolverConfig { coherence: true, globally: true };
}
true
@@ -1878,7 +1867,7 @@ options! {
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: bool = (true, parse_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes)"),
- next_solver: Option = (None, parse_next_solver_config, [TRACKED],
+ next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
"enable and configure the next generation trait solver used by rustc"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
"dump facts from NLL analysis into side files (default: no)"),
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 3476520960585..418d1078900ac 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -407,6 +407,7 @@ symbols! {
append_const_msg,
arbitrary_enum_discriminant,
arbitrary_self_types,
+ arbitrary_self_types_pointers,
args,
arith_offset,
arm,
@@ -1653,6 +1654,7 @@ symbols! {
rustc_lint_opt_deny_field_access,
rustc_lint_opt_ty,
rustc_lint_query_instability,
+ rustc_lint_untracked_query_information,
rustc_macro_transparency,
rustc_main,
rustc_mir,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f992ddf841704..6abd8a0d6b754 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1695,6 +1695,8 @@ supported_targets! {
("armv7r-none-eabihf", armv7r_none_eabihf),
("armv8r-none-eabihf", armv8r_none_eabihf),
+ ("armv7-rtems-eabihf", armv7_rtems_eabihf),
+
("x86_64-pc-solaris", x86_64_pc_solaris),
("sparcv9-sun-solaris", sparcv9_sun_solaris),
@@ -2097,9 +2099,10 @@ pub struct TargetOptions {
/// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
/// to "generic".
pub cpu: StaticCow,
- /// Default target features to pass to LLVM. These features will *always* be
- /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
- /// -mattr=$features`.
+ /// Default target features to pass to LLVM. These features overwrite
+ /// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
+ /// Corresponds to `llc -mattr=$features`.
+ /// Note that these are LLVM feature names, not Rust feature names!
pub features: StaticCow,
/// Direct or use GOT indirect to reference external data symbols
pub direct_access_external_data: Option,
diff --git a/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
new file mode 100644
index 0000000000000..1edecac095f6f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/armv7_rtems_eabihf.rs
@@ -0,0 +1,35 @@
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub(crate) fn target() -> Target {
+ Target {
+ llvm_target: "armv7-unknown-none-eabihf".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("Armv7 RTEMS (Requires RTEMS toolchain and kernel".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(true),
+ },
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+ arch: "arm".into(),
+
+ options: TargetOptions {
+ os: "rtems".into(),
+ families: cvs!["unix"],
+ abi: "eabihf".into(),
+ linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
+ linker: None,
+ relocation_model: RelocModel::Static,
+ panic_strategy: PanicStrategy::Abort,
+ features: "+thumb2,+neon,+vfp3".into(),
+ max_atomic_width: Some(64),
+ emit_debug_gdb_scripts: false,
+ // GCC defaults to 8 for arm-none here.
+ c_enum_min_bits: Some(8),
+ eh_frame_header: false,
+ no_default_libraries: false,
+ env: "newlib".into(),
+ ..Default::default()
+ },
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index bff2a184b19f0..65d21518491da 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -348,8 +348,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
- && ty.is_box()
- && ty.boxed_ty() == found
+ && ty.boxed_ty() == Some(found)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
{
err.span_suggestion(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index db71331d07f07..7bfc6471dc83f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::print::{FmtPrinter, Printer};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_span::def_id::DefId;
@@ -317,7 +317,7 @@ impl Trait for X {
{
let mut has_matching_impl = false;
tcx.for_each_relevant_impl(def_id, values.found, |did| {
- if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+ if DeepRejectCtxt::relate_rigid_infer(tcx)
.types_may_unify(values.found, tcx.type_of(did).skip_binder())
{
has_matching_impl = true;
@@ -338,7 +338,7 @@ impl Trait for X {
{
let mut has_matching_impl = false;
tcx.for_each_relevant_impl(def_id, values.expected, |did| {
- if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+ if DeepRejectCtxt::relate_rigid_infer(tcx)
.types_may_unify(values.expected, tcx.type_of(did).skip_binder())
{
has_matching_impl = true;
@@ -358,7 +358,7 @@ impl Trait for X {
{
let mut has_matching_impl = false;
tcx.for_each_relevant_impl(def_id, values.found, |did| {
- if DeepRejectCtxt::new(tcx, TreatParams::ForLookup)
+ if DeepRejectCtxt::relate_rigid_infer(tcx)
.types_may_unify(values.found, tcx.type_of(did).skip_binder())
{
has_matching_impl = true;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 5c663e0bf4b5b..45e157b108006 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5023,24 +5023,32 @@ impl<'v> Visitor<'v> for AwaitsVisitor {
}
}
+/// Suggest a new type parameter name for diagnostic purposes.
+///
+/// `name` is the preferred name you'd like to suggest if it's not in use already.
pub trait NextTypeParamName {
fn next_type_param_name(&self, name: Option<&str>) -> String;
}
impl NextTypeParamName for &[hir::GenericParam<'_>] {
fn next_type_param_name(&self, name: Option<&str>) -> String {
- // This is the list of possible parameter names that we might suggest.
+ // Type names are usually single letters in uppercase. So convert the first letter of input string to uppercase.
let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
let name = name.as_deref();
+
+ // This is the list of possible parameter names that we might suggest.
let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
- let used_names = self
+
+ // Filter out used names based on `filter_fn`.
+ let used_names: Vec = self
.iter()
- .filter_map(|p| match p.name {
+ .filter_map(|param| match param.name {
hir::ParamName::Plain(ident) => Some(ident.name),
_ => None,
})
- .collect::>();
+ .collect();
+ // Find a name from `possible_names` that is not in `used_names`.
possible_names
.iter()
.find(|n| !used_names.contains(&Symbol::intern(n)))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8558520897b5c..bafe1ffae44d3 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -15,7 +15,7 @@ use rustc_middle::bug;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
use rustc_middle::traits::specialization_graph::OverlapMode;
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
pub use rustc_next_trait_solver::coherence::*;
@@ -29,6 +29,7 @@ use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::InferOk;
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::solve::{deeply_normalize_for_diagnostics, inspect};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::{
util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
@@ -95,7 +96,7 @@ pub fn overlapping_impls(
// Before doing expensive operations like entering an inference context, do
// a quick check via fast_reject to tell if the impl headers could possibly
// unify.
- let drcx = DeepRejectCtxt::new(tcx, TreatParams::AsCandidateKey);
+ let drcx = DeepRejectCtxt::relate_infer_infer(tcx);
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
let may_overlap = match (impl1_ref, impl2_ref) {
@@ -624,14 +625,13 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
// at ambiguous goals, as for others the coherence unknowable candidate
// was irrelevant.
match goal.result() {
- Ok(Certainty::Maybe(_)) => {}
Ok(Certainty::Yes) | Err(NoSolution) => return,
+ Ok(Certainty::Maybe(_)) => {}
}
- let Goal { param_env, predicate } = goal.goal();
-
// For bound predicates we simply call `infcx.enter_forall`
// and then prove the resulting predicate as a nested goal.
+ let Goal { param_env, predicate } = goal.goal();
let trait_ref = match predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
@@ -645,7 +645,11 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
_ => return,
};
- // Add ambiguity causes for reservation impls.
+ if trait_ref.references_error() {
+ return;
+ }
+
+ let mut candidates = goal.candidates();
for cand in goal.candidates() {
if let inspect::ProbeKind::TraitCandidate {
source: CandidateSource::Impl(def_id),
@@ -664,78 +668,68 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
}
}
- // Add ambiguity causes for unknowable goals.
- let mut ambiguity_cause = None;
- for cand in goal.candidates() {
- if let inspect::ProbeKind::TraitCandidate {
- source: CandidateSource::CoherenceUnknowable,
- result: Ok(_),
- } = cand.kind()
- {
- let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
- if matches!(ty.kind(), ty::Alias(..)) {
- let ocx = ObligationCtxt::new(infcx);
- ty = ocx
- .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
- .map_err(|_| ())?;
- if !ocx.select_where_possible().is_empty() {
- return Err(());
- }
- }
- Ok(ty)
- };
+ // We also look for unknowable candidates. In case a goal is unknowable, there's
+ // always exactly 1 candidate.
+ let Some(cand) = candidates.pop() else {
+ return;
+ };
- infcx.probe(|_| {
- match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
- Err(()) => {}
- Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
- Ok(Err(conflict)) => {
- if !trait_ref.references_error() {
- // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
- let trait_ref =
- deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
-
- let self_ty = trait_ref.self_ty();
- let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
- ambiguity_cause = Some(match conflict {
- Conflict::Upstream => {
- IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_ref,
- self_ty,
- }
- }
- Conflict::Downstream => {
- IntercrateAmbiguityCause::DownstreamCrate {
- trait_ref,
- self_ty,
- }
- }
- });
- }
- }
- }
- })
- } else {
- match cand.result() {
- // We only add an ambiguity cause if the goal would otherwise
- // result in an error.
- //
- // FIXME: While this matches the behavior of the
- // old solver, it is not the only way in which the unknowable
- // candidates *weaken* coherence, they can also force otherwise
- // successful normalization to be ambiguous.
- Ok(Certainty::Maybe(_) | Certainty::Yes) => {
- ambiguity_cause = None;
- break;
- }
- Err(NoSolution) => continue,
+ let inspect::ProbeKind::TraitCandidate {
+ source: CandidateSource::CoherenceUnknowable,
+ result: Ok(_),
+ } = cand.kind()
+ else {
+ return;
+ };
+
+ let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
+ if matches!(ty.kind(), ty::Alias(..)) {
+ let ocx = ObligationCtxt::new(infcx);
+ ty = ocx
+ .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+ .map_err(|_| ())?;
+ if !ocx.select_where_possible().is_empty() {
+ return Err(());
}
}
- }
+ Ok(ty)
+ };
- if let Some(ambiguity_cause) = ambiguity_cause {
- self.causes.insert(ambiguity_cause);
- }
+ infcx.probe(|_| {
+ let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
+ Err(()) => return,
+ Ok(Ok(())) => {
+ warn!("expected an unknowable trait ref: {trait_ref:?}");
+ return;
+ }
+ Ok(Err(conflict)) => conflict,
+ };
+
+ // It is only relevant that a goal is unknowable if it would have otherwise
+ // failed.
+ let non_intercrate_infcx = infcx.fork_with_intercrate(false);
+ if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
+ infcx.tcx,
+ ObligationCause::dummy(),
+ param_env,
+ predicate,
+ )) {
+ return;
+ }
+
+ // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+ let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+ let self_ty = trait_ref.self_ty();
+ let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
+ self.causes.insert(match conflict {
+ Conflict::Upstream => {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
+ }
+ Conflict::Downstream => {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
+ }
+ });
+ });
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index de1d4ef15aced..c8811bc37b310 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -35,10 +35,8 @@ where
if infcx.next_trait_solver() {
Box::new(NextFulfillmentCtxt::new(infcx))
} else {
- let new_solver_globally =
- infcx.tcx.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally);
assert!(
- !new_solver_globally,
+ !infcx.tcx.next_trait_solver_globally(),
"using old solver even though new solver is enabled globally"
);
Box::new(FulfillmentContext::new(infcx))
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 4702fd866c1b6..630acc91fbedc 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -13,6 +13,7 @@ use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::select::OverflowError;
pub use rustc_middle::traits::Reveal;
use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData};
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast};
@@ -886,6 +887,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
potentially_unnormalized_candidates: bool,
) {
let infcx = selcx.infcx;
+ let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
for predicate in env_predicates {
let bound_predicate = predicate.kind();
if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() {
@@ -894,6 +896,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
continue;
}
+ if !drcx
+ .args_may_unify(obligation.predicate.args, data.skip_binder().projection_term.args)
+ {
+ continue;
+ }
+
let is_match = infcx.probe(|_| {
selcx.match_projection_projections(
obligation,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 96faa5236b198..77efc2fc2dbfd 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -13,7 +13,7 @@ use hir::LangItem;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation, SelectionError};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use tracing::{debug, instrument, trace};
@@ -248,11 +248,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.filter(|p| p.def_id() == stack.obligation.predicate.def_id())
.filter(|p| p.polarity() == stack.obligation.predicate.polarity());
+ let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx());
+ let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args;
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in bounds {
+ let bound_trait_ref = bound.map_bound(|t| t.trait_ref);
+ if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
+ continue;
+ }
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here.
- let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
+ let wc = self.where_clause_may_apply(stack, bound_trait_ref)?;
if wc.may_apply() {
candidates.vec.push(ParamCandidate(bound));
}
@@ -581,7 +587,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
- let drcx = DeepRejectCtxt::new(self.tcx(), TreatParams::ForLookup);
+ let drcx = DeepRejectCtxt::relate_rigid_infer(self.tcx());
let obligation_args = obligation.predicate.skip_binder().trait_ref.args;
self.tcx().for_each_relevant_impl(
obligation.predicate.def_id(),
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 0fdaf40b136d8..13620f4b8d9cc 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -41,7 +41,7 @@ impl<'tcx> Children {
fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
if let Some(st) =
- fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer)
{
debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
@@ -58,7 +58,7 @@ impl<'tcx> Children {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder();
let vec: &mut Vec;
if let Some(st) =
- fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey)
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer)
{
debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
vec = self.non_blanket_impls.get_mut(&st).unwrap();
@@ -279,7 +279,7 @@ impl<'tcx> Graph {
let mut parent = trait_def_id;
let mut last_lint = None;
let simplified =
- fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey);
+ fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::InstantiateWithInfer);
// Descend the specialization tree, where `parent` is the current parent node.
loop {
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index fab4a0991175d..2c8e47bcbca2a 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -74,13 +74,13 @@ impl> ToStableHashKey for SimplifiedType
pub enum TreatParams {
/// Treat parameters as infer vars. This is the correct mode for caching
/// an impl's type for lookup.
- AsCandidateKey,
+ InstantiateWithInfer,
/// Treat parameters as placeholders in the given environment. This is the
/// correct mode for *lookup*, as during candidate selection.
///
/// This also treats projections with inference variables as infer vars
/// since they could be further normalized.
- ForLookup,
+ AsRigid,
}
/// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
@@ -140,18 +140,16 @@ pub fn simplify_type(
}
ty::Placeholder(..) => Some(SimplifiedType::Placeholder),
ty::Param(_) => match treat_params {
- TreatParams::ForLookup => Some(SimplifiedType::Placeholder),
- TreatParams::AsCandidateKey => None,
+ TreatParams::AsRigid => Some(SimplifiedType::Placeholder),
+ TreatParams::InstantiateWithInfer => None,
},
ty::Alias(..) => match treat_params {
// When treating `ty::Param` as a placeholder, projections also
// don't unify with anything else as long as they are fully normalized.
// FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder`
// when the new solver is enabled by default.
- TreatParams::ForLookup if !ty.has_non_region_infer() => {
- Some(SimplifiedType::Placeholder)
- }
- TreatParams::ForLookup | TreatParams::AsCandidateKey => None,
+ TreatParams::AsRigid if !ty.has_non_region_infer() => Some(SimplifiedType::Placeholder),
+ TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None,
},
ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
ty::Error(_) => Some(SimplifiedType::Error),
@@ -173,29 +171,49 @@ impl SimplifiedType {
}
}
-/// Given generic arguments from an obligation and an impl,
-/// could these two be unified after replacing parameters in the
-/// the impl with inference variables.
+/// Given generic arguments, could they be unified after
+/// replacing parameters with inference variables or placeholders.
+/// This behavior is toggled using the const generics.
///
-/// For obligations, parameters won't be replaced by inference
-/// variables and only unify with themselves. We treat them
-/// the same way we treat placeholders.
+/// We use this to quickly reject impl/wc candidates without needing
+/// to instantiate generic arguments/having to enter a probe.
///
/// We also use this function during coherence. For coherence the
/// impls only have to overlap for some value, so we treat parameters
-/// on both sides like inference variables. This behavior is toggled
-/// using the `treat_obligation_params` field.
+/// on both sides like inference variables.
#[derive(Debug, Clone, Copy)]
-pub struct DeepRejectCtxt {
- treat_obligation_params: TreatParams,
+pub struct DeepRejectCtxt<
+ I: Interner,
+ const INSTANTIATE_LHS_WITH_INFER: bool,
+ const INSTANTIATE_RHS_WITH_INFER: bool,
+> {
_interner: PhantomData,
}
-impl DeepRejectCtxt {
- pub fn new(_interner: I, treat_obligation_params: TreatParams) -> Self {
- DeepRejectCtxt { treat_obligation_params, _interner: PhantomData }
+impl DeepRejectCtxt {
+ /// Treat parameters in both the lhs and the rhs as rigid.
+ pub fn relate_rigid_rigid(_interner: I) -> DeepRejectCtxt {
+ DeepRejectCtxt { _interner: PhantomData }
+ }
+}
+
+impl DeepRejectCtxt {
+ /// Treat parameters in both the lhs and the rhs as infer vars.
+ pub fn relate_infer_infer(_interner: I) -> DeepRejectCtxt {
+ DeepRejectCtxt { _interner: PhantomData }
}
+}
+impl DeepRejectCtxt {
+ /// Treat parameters in the lhs as rigid, and in rhs as infer vars.
+ pub fn relate_rigid_infer(_interner: I) -> DeepRejectCtxt {
+ DeepRejectCtxt { _interner: PhantomData }
+ }
+}
+
+impl
+ DeepRejectCtxt
+{
pub fn args_may_unify(
self,
obligation_args: I::GenericArgs,
@@ -216,11 +234,18 @@ impl DeepRejectCtxt {
})
}
- pub fn types_may_unify(self, obligation_ty: I::Ty, impl_ty: I::Ty) -> bool {
- match impl_ty.kind() {
- // Start by checking whether the type in the impl may unify with
+ pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
+ match rhs.kind() {
+ // Start by checking whether the `rhs` type may unify with
// pretty much everything. Just return `true` in that case.
- ty::Param(_) | ty::Error(_) | ty::Alias(..) => return true,
+ ty::Param(_) => {
+ if INSTANTIATE_RHS_WITH_INFER {
+ return true;
+ }
+ }
+ ty::Error(_) | ty::Alias(..) | ty::Bound(..) => return true,
+ ty::Infer(var) => return self.var_and_ty_may_unify(var, lhs),
+
// These types only unify with inference variables or their own
// variant.
ty::Bool
@@ -238,159 +263,217 @@ impl DeepRejectCtxt {
| ty::Ref(..)
| ty::Never
| ty::Tuple(..)
+ | ty::FnDef(..)
| ty::FnPtr(..)
- | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()),
- ty::FnDef(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
- | ty::Placeholder(..)
- | ty::Bound(..)
- | ty::Infer(_) => panic!("unexpected impl_ty: {impl_ty:?}"),
- }
+ | ty::Foreign(_)
+ | ty::Placeholder(_) => {}
+ };
- let k = impl_ty.kind();
- match obligation_ty.kind() {
- // Purely rigid types, use structural equivalence.
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Never
- | ty::Foreign(_) => obligation_ty == impl_ty,
- ty::Ref(_, obl_ty, obl_mutbl) => match k {
- ty::Ref(_, impl_ty, impl_mutbl) => {
- obl_mutbl == impl_mutbl && self.types_may_unify(obl_ty, impl_ty)
+ // For purely rigid types, use structural equivalence.
+ match lhs.kind() {
+ ty::Ref(_, lhs_ty, lhs_mutbl) => match rhs.kind() {
+ ty::Ref(_, rhs_ty, rhs_mutbl) => {
+ lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty)
}
_ => false,
},
- ty::Adt(obl_def, obl_args) => match k {
- ty::Adt(impl_def, impl_args) => {
- obl_def == impl_def && self.args_may_unify(obl_args, impl_args)
+
+ ty::Adt(lhs_def, lhs_args) => match rhs.kind() {
+ ty::Adt(rhs_def, rhs_args) => {
+ lhs_def == rhs_def && self.args_may_unify(lhs_args, rhs_args)
}
_ => false,
},
- ty::Pat(obl_ty, _) => {
- // FIXME(pattern_types): take pattern into account
- matches!(k, ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
+
+ // Depending on the value of const generics, we either treat generic parameters
+ // like placeholders or like inference variables.
+ ty::Param(lhs) => {
+ INSTANTIATE_LHS_WITH_INFER
+ || match rhs.kind() {
+ ty::Param(rhs) => lhs == rhs,
+ _ => false,
+ }
}
- ty::Slice(obl_ty) => {
- matches!(k, ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
+
+ // Placeholder types don't unify with anything on their own.
+ ty::Placeholder(lhs) => {
+ matches!(rhs.kind(), ty::Placeholder(rhs) if lhs == rhs)
}
- ty::Array(obl_ty, obl_len) => match k {
- ty::Array(impl_ty, impl_len) => {
- self.types_may_unify(obl_ty, impl_ty)
- && self.consts_may_unify(obl_len, impl_len)
+
+ ty::Infer(var) => self.var_and_ty_may_unify(var, rhs),
+
+ // As we're walking the whole type, it may encounter projections
+ // inside of binders and what not, so we're just going to assume that
+ // projections can unify with other stuff.
+ //
+ // Looking forward to lazy normalization this is the safer strategy anyways.
+ ty::Alias(..) => true,
+
+ ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Bool
+ | ty::Char
+ | ty::Never
+ | ty::Foreign(_) => lhs == rhs,
+
+ ty::Tuple(lhs) => match rhs.kind() {
+ ty::Tuple(rhs) => {
+ lhs.len() == rhs.len()
+ && iter::zip(lhs.iter(), rhs.iter())
+ .all(|(lhs, rhs)| self.types_may_unify(lhs, rhs))
}
_ => false,
},
- ty::Tuple(obl) => match k {
- ty::Tuple(imp) => {
- obl.len() == imp.len()
- && iter::zip(obl.iter(), imp.iter())
- .all(|(obl, imp)| self.types_may_unify(obl, imp))
+
+ ty::Array(lhs_ty, lhs_len) => match rhs.kind() {
+ ty::Array(rhs_ty, rhs_len) => {
+ self.types_may_unify(lhs_ty, rhs_ty) && self.consts_may_unify(lhs_len, rhs_len)
}
_ => false,
},
- ty::RawPtr(obl_ty, obl_mutbl) => match k {
- ty::RawPtr(imp_ty, imp_mutbl) => {
- obl_mutbl == imp_mutbl && self.types_may_unify(obl_ty, imp_ty)
+
+ ty::RawPtr(lhs_ty, lhs_mutbl) => match rhs.kind() {
+ ty::RawPtr(rhs_ty, rhs_mutbl) => {
+ lhs_mutbl == rhs_mutbl && self.types_may_unify(lhs_ty, rhs_ty)
}
_ => false,
},
- ty::Dynamic(obl_preds, ..) => {
+
+ ty::Slice(lhs_ty) => {
+ matches!(rhs.kind(), ty::Slice(rhs_ty) if self.types_may_unify(lhs_ty, rhs_ty))
+ }
+
+ ty::Dynamic(lhs_preds, ..) => {
// Ideally we would walk the existential predicates here or at least
// compare their length. But considering that the relevant `Relate` impl
// actually sorts and deduplicates these, that doesn't work.
- matches!(k, ty::Dynamic(impl_preds, ..) if
- obl_preds.principal_def_id() == impl_preds.principal_def_id()
+ matches!(rhs.kind(), ty::Dynamic(rhs_preds, ..) if
+ lhs_preds.principal_def_id() == rhs_preds.principal_def_id()
)
}
- ty::FnPtr(obl_sig_tys, obl_hdr) => match k {
- ty::FnPtr(impl_sig_tys, impl_hdr) => {
- let obl_sig_tys = obl_sig_tys.skip_binder().inputs_and_output;
- let impl_sig_tys = impl_sig_tys.skip_binder().inputs_and_output;
-
- obl_hdr == impl_hdr
- && obl_sig_tys.len() == impl_sig_tys.len()
- && iter::zip(obl_sig_tys.iter(), impl_sig_tys.iter())
- .all(|(obl, imp)| self.types_may_unify(obl, imp))
+
+ ty::FnPtr(lhs_sig_tys, lhs_hdr) => match rhs.kind() {
+ ty::FnPtr(rhs_sig_tys, rhs_hdr) => {
+ let lhs_sig_tys = lhs_sig_tys.skip_binder().inputs_and_output;
+ let rhs_sig_tys = rhs_sig_tys.skip_binder().inputs_and_output;
+
+ lhs_hdr == rhs_hdr
+ && lhs_sig_tys.len() == rhs_sig_tys.len()
+ && iter::zip(lhs_sig_tys.iter(), rhs_sig_tys.iter())
+ .all(|(lhs, rhs)| self.types_may_unify(lhs, rhs))
}
_ => false,
},
- // Impls cannot contain these types as these cannot be named directly.
- ty::FnDef(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => false,
-
- // Placeholder types don't unify with anything on their own
- ty::Placeholder(..) | ty::Bound(..) => false,
+ ty::Bound(..) => true,
- // Depending on the value of `treat_obligation_params`, we either
- // treat generic parameters like placeholders or like inference variables.
- ty::Param(_) => match self.treat_obligation_params {
- TreatParams::ForLookup => false,
- TreatParams::AsCandidateKey => true,
+ ty::FnDef(lhs_def_id, lhs_args) => match rhs.kind() {
+ ty::FnDef(rhs_def_id, rhs_args) => {
+ lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args)
+ }
+ _ => false,
},
- ty::Infer(ty::IntVar(_)) => impl_ty.is_integral(),
-
- ty::Infer(ty::FloatVar(_)) => impl_ty.is_floating_point(),
+ ty::Closure(lhs_def_id, lhs_args) => match rhs.kind() {
+ ty::Closure(rhs_def_id, rhs_args) => {
+ lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args)
+ }
+ _ => false,
+ },
- ty::Infer(_) => true,
+ ty::CoroutineClosure(lhs_def_id, lhs_args) => match rhs.kind() {
+ ty::CoroutineClosure(rhs_def_id, rhs_args) => {
+ lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args)
+ }
+ _ => false,
+ },
- // As we're walking the whole type, it may encounter projections
- // inside of binders and what not, so we're just going to assume that
- // projections can unify with other stuff.
- //
- // Looking forward to lazy normalization this is the safer strategy anyways.
- ty::Alias(..) => true,
+ ty::Coroutine(lhs_def_id, lhs_args) => match rhs.kind() {
+ ty::Coroutine(rhs_def_id, rhs_args) => {
+ lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args)
+ }
+ _ => false,
+ },
- ty::Error(_) => true,
+ ty::CoroutineWitness(lhs_def_id, lhs_args) => match rhs.kind() {
+ ty::CoroutineWitness(rhs_def_id, rhs_args) => {
+ lhs_def_id == rhs_def_id && self.args_may_unify(lhs_args, rhs_args)
+ }
+ _ => false,
+ },
- ty::CoroutineWitness(..) => {
- panic!("unexpected obligation type: {:?}", obligation_ty)
+ ty::Pat(lhs_ty, _) => {
+ // FIXME(pattern_types): take pattern into account
+ matches!(rhs.kind(), ty::Pat(rhs_ty, _) if self.types_may_unify(lhs_ty, rhs_ty))
}
+
+ ty::Error(..) => true,
}
}
- pub fn consts_may_unify(self, obligation_ct: I::Const, impl_ct: I::Const) -> bool {
- let impl_val = match impl_ct.kind() {
+ pub fn consts_may_unify(self, lhs: I::Const, rhs: I::Const) -> bool {
+ match rhs.kind() {
+ ty::ConstKind::Param(_) => {
+ if INSTANTIATE_RHS_WITH_INFER {
+ return true;
+ }
+ }
+
ty::ConstKind::Expr(_)
- | ty::ConstKind::Param(_)
| ty::ConstKind::Unevaluated(_)
- | ty::ConstKind::Error(_) => {
+ | ty::ConstKind::Error(_)
+ | ty::ConstKind::Infer(_)
+ | ty::ConstKind::Bound(..) => {
return true;
}
- ty::ConstKind::Value(_, impl_val) => impl_val,
- ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
- panic!("unexpected impl arg: {:?}", impl_ct)
- }
+
+ ty::ConstKind::Value(..) | ty::ConstKind::Placeholder(_) => {}
};
- match obligation_ct.kind() {
- ty::ConstKind::Param(_) => match self.treat_obligation_params {
- TreatParams::ForLookup => false,
- TreatParams::AsCandidateKey => true,
+ match lhs.kind() {
+ ty::ConstKind::Value(_, lhs_val) => match rhs.kind() {
+ ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val,
+ _ => false,
},
+ ty::ConstKind::Param(lhs) => {
+ INSTANTIATE_LHS_WITH_INFER
+ || match rhs.kind() {
+ ty::ConstKind::Param(rhs) => lhs == rhs,
+ _ => false,
+ }
+ }
+
// Placeholder consts don't unify with anything on their own
- ty::ConstKind::Placeholder(_) => false,
+ ty::ConstKind::Placeholder(lhs) => {
+ matches!(rhs.kind(), ty::ConstKind::Placeholder(rhs) if lhs == rhs)
+ }
// As we don't necessarily eagerly evaluate constants,
// they might unify with any value.
ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => {
true
}
- ty::ConstKind::Value(_, obl_val) => obl_val == impl_val,
- ty::ConstKind::Infer(_) => true,
+ ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) => true,
+ }
+ }
- ty::ConstKind::Bound(..) => {
- panic!("unexpected obl const: {:?}", obligation_ct)
- }
+ fn var_and_ty_may_unify(self, var: ty::InferTy, ty: I::Ty) -> bool {
+ if !ty.is_known_rigid() {
+ return true;
+ }
+
+ match var {
+ ty::IntVar(_) => ty.is_integral(),
+ ty::FloatVar(_) => ty.is_floating_point(),
+ _ => true,
}
}
}
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index 96c939a898bd9..96998d2ec9f2c 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -58,7 +58,7 @@ pub enum Reveal {
All,
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SolverMode {
/// Ordinary trait solving, using everywhere except for coherence.
Normal,
diff --git a/config.example.toml b/config.example.toml
index b967d5d9fe8c2..e9433c9c9bd08 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -78,6 +78,9 @@
# Indicates whether the LLVM plugin is enabled or not
#plugins = false
+# Wheter to build Enzyme as AutoDiff backend.
+#enzyme = false
+
# Indicates whether ccache is used when building LLVM. Set to `true` to use the first `ccache` in
# PATH, or set an absolute path to use a specific version.
#ccache = false
@@ -519,6 +522,9 @@
# are disabled statically" because `max_level_info` is enabled, set this value to `true`.
#debug-logging = rust.debug-assertions (boolean)
+# Whether or not to build rustc, tools and the libraries with randomized type layout
+#randomize-layout = false
+
# Whether or not overflow checks are enabled for the compiler and standard
# library.
#
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 4365bcc4ad022..1bd4434d4f7e9 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -52,4 +52,5 @@ check-cfg = [
'cfg(no_global_oom_handling)',
'cfg(no_rc)',
'cfg(no_sync)',
+ 'cfg(randomized_layouts)',
]
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index d230749d71231..4d2fa0f094171 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -90,7 +90,7 @@ fn test_partial_eq() {
#[test]
#[cfg(target_arch = "x86_64")]
-#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization
+#[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization
fn test_sizes() {
assert_eq!(core::mem::size_of::>(), 16);
assert_eq!(core::mem::size_of::>(), 16 + CAPACITY * 2 * 8);
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index cace4582b489a..94f343d06705e 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -43,6 +43,8 @@ check-cfg = [
'cfg(bootstrap)',
'cfg(no_fp_fmt_parse)',
'cfg(stdarch_intel_sde)',
+ # #[cfg(bootstrap)] rtems
+ 'cfg(target_os, values("rtems"))',
# core use #[path] imports to portable-simd `core_simd` crate
# and to stdarch `core_arch` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index ec1f9052a1564..dc107c5d22cdd 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -110,7 +110,7 @@ mod c_char_definition {
all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
all(target_os = "l4re", target_arch = "x86_64"),
all(
- any(target_os = "freebsd", target_os = "openbsd"),
+ any(target_os = "freebsd", target_os = "openbsd", target_os = "rtems"),
any(
target_arch = "aarch64",
target_arch = "arm",
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 5654f5aa4b8d2..d9f197d9510ef 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -288,8 +288,19 @@ marker_impls! {
/// }
/// ```
///
-/// There is a small difference between the two: the `derive` strategy will also place a `Copy`
-/// bound on type parameters, which isn't always desired.
+/// There is a small difference between the two. The `derive` strategy will also place a `Copy`
+/// bound on type parameters:
+///
+/// ```
+/// #[derive(Clone)]
+/// struct MyStruct(T);
+///
+/// impl Copy for MyStruct { }
+/// ```
+///
+/// This isn't always desired. For example, shared references (`&T`) can be copied regardless of
+/// whether `T` is `Copy`. Likewise, a generic struct containing markers such as [`PhantomData`]
+/// could potentially be duplicated with a bit-wise copy.
///
/// ## What's the difference between `Copy` and `Clone`?
///
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index d7ed4edcc0041..08d06cad55d06 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -2277,6 +2277,14 @@ impl fmt::Debug for F {
/// `addr_of!(expr)` is equivalent to `&raw const expr`. The macro is *soft-deprecated*;
/// use `&raw const` instead.
///
+/// It is still an open question under which conditions writing through an `addr_of!`-created
+/// pointer is permitted. If the place `expr` evaluates to is based on a raw pointer, then the
+/// result of `addr_of!` inherits all permissions from that raw pointer. However, if the place is
+/// based on a reference, local variable, or `static`, then until all details are decided, the same
+/// rules as for shared references apply: it is UB to write through a pointer created with this
+/// operation, except for bytes located inside an `UnsafeCell`. Use `&raw mut` (or [`addr_of_mut`])
+/// to create a raw pointer that definitely permits mutation.
+///
/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned
/// and points to initialized data. For cases where those requirements do not hold,
/// raw pointers should be used instead. However, `&expr as *const _` creates a reference
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 7e5c1574f5367..6924b3c13ece3 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -60,22 +60,6 @@ impl RawWaker {
RawWaker { data, vtable }
}
- /// Gets the `data` pointer used to create this `RawWaker`.
- #[inline]
- #[must_use]
- #[unstable(feature = "waker_getters", issue = "96992")]
- pub fn data(&self) -> *const () {
- self.data
- }
-
- /// Gets the `vtable` pointer used to create this `RawWaker`.
- #[inline]
- #[must_use]
- #[unstable(feature = "waker_getters", issue = "96992")]
- pub fn vtable(&self) -> &'static RawWakerVTable {
- self.vtable
- }
-
#[unstable(feature = "noop_waker", issue = "98286")]
const NOOP: RawWaker = {
const VTABLE: RawWakerVTable = RawWakerVTable::new(
@@ -509,6 +493,37 @@ impl Waker {
a_data == b_data && ptr::eq(a_vtable, b_vtable)
}
+ /// Creates a new `Waker` from the provided `data` pointer and `vtable`.
+ ///
+ /// The `data` pointer can be used to store arbitrary data as required
+ /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
+ /// that is associated with the task.
+ /// The value of this pointer will get passed to all functions that are part
+ /// of the `vtable` as the first parameter.
+ ///
+ /// It is important to consider that the `data` pointer must point to a
+ /// thread safe type such as an `Arc`.
+ ///
+ /// The `vtable` customizes the behavior of a `Waker`. For each operation
+ /// on the `Waker`, the associated function in the `vtable` will be called.
+ ///
+ /// # Safety
+ ///
+ /// The behavior of the returned `Waker` is undefined if the contract defined
+ /// in [`RawWakerVTable`]'s documentation is not upheld.
+ ///
+ /// (Authors wishing to avoid unsafe code may implement the [`Wake`] trait instead, at the
+ /// cost of a required heap allocation.)
+ ///
+ /// [`Wake`]: ../../alloc/task/trait.Wake.html
+ #[inline]
+ #[must_use]
+ #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+ pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
+ Waker { waker: RawWaker { data, vtable } }
+ }
+
/// Creates a new `Waker` from [`RawWaker`].
///
/// # Safety
@@ -565,12 +580,20 @@ impl Waker {
WAKER
}
- /// Gets a reference to the underlying [`RawWaker`].
+ /// Gets the `data` pointer used to create this `Waker`.
#[inline]
#[must_use]
- #[unstable(feature = "waker_getters", issue = "96992")]
- pub fn as_raw(&self) -> &RawWaker {
- &self.waker
+ #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+ pub fn data(&self) -> *const () {
+ self.waker.data
+ }
+
+ /// Gets the `vtable` pointer used to create this `Waker`.
+ #[inline]
+ #[must_use]
+ #[stable(feature = "waker_getters", since = "CURRENT_RUSTC_VERSION")]
+ pub fn vtable(&self) -> &'static RawWakerVTable {
+ self.waker.vtable
}
}
@@ -778,6 +801,30 @@ impl LocalWaker {
a_data == b_data && ptr::eq(a_vtable, b_vtable)
}
+ /// Creates a new `LocalWaker` from the provided `data` pointer and `vtable`.
+ ///
+ /// The `data` pointer can be used to store arbitrary data as required
+ /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
+ /// that is associated with the task.
+ /// The value of this pointer will get passed to all functions that are part
+ /// of the `vtable` as the first parameter.
+ ///
+ /// The `vtable` customizes the behavior of a `LocalWaker`. For each
+ /// operation on the `LocalWaker`, the associated function in the `vtable`
+ /// will be called.
+ ///
+ /// # Safety
+ ///
+ /// The behavior of the returned `Waker` is undefined if the contract defined
+ /// in [`RawWakerVTable`]'s documentation is not upheld.
+ ///
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "local_waker", issue = "118959")]
+ pub const unsafe fn new(data: *const (), vtable: &'static RawWakerVTable) -> Self {
+ LocalWaker { waker: RawWaker { data, vtable } }
+ }
+
/// Creates a new `LocalWaker` from [`RawWaker`].
///
/// The behavior of the returned `LocalWaker` is undefined if the contract defined
@@ -831,12 +878,20 @@ impl LocalWaker {
WAKER
}
- /// Gets a reference to the underlying [`RawWaker`].
+ /// Gets the `data` pointer used to create this `LocalWaker`.
#[inline]
#[must_use]
- #[unstable(feature = "waker_getters", issue = "96992")]
- pub fn as_raw(&self) -> &RawWaker {
- &self.waker
+ #[unstable(feature = "local_waker", issue = "118959")]
+ pub fn data(&self) -> *const () {
+ self.waker.data
+ }
+
+ /// Gets the `vtable` pointer used to create this `LocalWaker`.
+ #[inline]
+ #[must_use]
+ #[unstable(feature = "local_waker", issue = "118959")]
+ pub fn vtable(&self) -> &'static RawWakerVTable {
+ self.waker.vtable
}
}
#[unstable(feature = "local_waker", issue = "118959")]
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 0390bb59a8984..c19eeedb35426 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -250,7 +250,7 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::from_millis(2569);
+ /// let duration = Duration::from_millis(2_569);
///
/// assert_eq!(2, duration.as_secs());
/// assert_eq!(569_000_000, duration.subsec_nanos());
@@ -279,7 +279,7 @@ impl Duration {
/// let duration = Duration::from_micros(1_000_002);
///
/// assert_eq!(1, duration.as_secs());
- /// assert_eq!(2000, duration.subsec_nanos());
+ /// assert_eq!(2_000, duration.subsec_nanos());
/// ```
#[stable(feature = "duration_from_micros", since = "1.27.0")]
#[must_use]
@@ -472,7 +472,7 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::new(5, 730023852);
+ /// let duration = Duration::new(5, 730_023_852);
/// assert_eq!(duration.as_secs(), 5);
/// ```
///
@@ -501,7 +501,7 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::from_millis(5432);
+ /// let duration = Duration::from_millis(5_432);
/// assert_eq!(duration.as_secs(), 5);
/// assert_eq!(duration.subsec_millis(), 432);
/// ```
@@ -547,7 +547,7 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::from_millis(5010);
+ /// let duration = Duration::from_millis(5_010);
/// assert_eq!(duration.as_secs(), 5);
/// assert_eq!(duration.subsec_nanos(), 10_000_000);
/// ```
@@ -566,8 +566,8 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::new(5, 730023852);
- /// assert_eq!(duration.as_millis(), 5730);
+ /// let duration = Duration::new(5, 730_023_852);
+ /// assert_eq!(duration.as_millis(), 5_730);
/// ```
#[stable(feature = "duration_as_u128", since = "1.33.0")]
#[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
@@ -584,8 +584,8 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::new(5, 730023852);
- /// assert_eq!(duration.as_micros(), 5730023);
+ /// let duration = Duration::new(5, 730_023_852);
+ /// assert_eq!(duration.as_micros(), 5_730_023);
/// ```
#[stable(feature = "duration_as_u128", since = "1.33.0")]
#[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
@@ -602,8 +602,8 @@ impl Duration {
/// ```
/// use std::time::Duration;
///
- /// let duration = Duration::new(5, 730023852);
- /// assert_eq!(duration.as_nanos(), 5730023852);
+ /// let duration = Duration::new(5, 730_023_852);
+ /// assert_eq!(duration.as_nanos(), 5_730_023_852);
/// ```
#[stable(feature = "duration_as_u128", since = "1.33.0")]
#[rustc_const_stable(feature = "duration_as_u128", since = "1.33.0")]
@@ -879,7 +879,7 @@ impl Duration {
/// use std::time::Duration;
///
/// let dur = Duration::new(2, 345_678_000);
- /// assert_eq!(dur.as_millis_f64(), 2345.678);
+ /// assert_eq!(dur.as_millis_f64(), 2_345.678);
/// ```
#[unstable(feature = "duration_millis_float", issue = "122451")]
#[must_use]
@@ -900,7 +900,7 @@ impl Duration {
/// use std::time::Duration;
///
/// let dur = Duration::new(2, 345_678_000);
- /// assert_eq!(dur.as_millis_f32(), 2345.678);
+ /// assert_eq!(dur.as_millis_f32(), 2_345.678);
/// ```
#[unstable(feature = "duration_millis_float", issue = "122451")]
#[must_use]
@@ -1017,7 +1017,7 @@ impl Duration {
///
/// let dur = Duration::new(2, 700_000_000);
/// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641));
- /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
+ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use = "this returns the result of the operation, \
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c205f028dd3a7..96fc621494f2a 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -112,7 +112,6 @@
#![feature(unsize)]
#![feature(unsized_tuple_coercion)]
#![feature(unwrap_infallible)]
-#![feature(waker_getters)]
// tidy-alphabetical-end
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs
index 361e900e69562..8f6bf0565fc35 100644
--- a/library/core/tests/waker.rs
+++ b/library/core/tests/waker.rs
@@ -4,14 +4,13 @@ use std::task::{RawWaker, RawWakerVTable, Waker};
#[test]
fn test_waker_getters() {
let raw_waker = RawWaker::new(ptr::without_provenance_mut(42usize), &WAKER_VTABLE);
- assert_eq!(raw_waker.data() as usize, 42);
- assert!(ptr::eq(raw_waker.vtable(), &WAKER_VTABLE));
-
let waker = unsafe { Waker::from_raw(raw_waker) };
+ assert_eq!(waker.data() as usize, 42);
+ assert!(ptr::eq(waker.vtable(), &WAKER_VTABLE));
+
let waker2 = waker.clone();
- let raw_waker2 = waker2.as_raw();
- assert_eq!(raw_waker2.data() as usize, 43);
- assert!(ptr::eq(raw_waker2.vtable(), &WAKER_VTABLE));
+ assert_eq!(waker2.data() as usize, 43);
+ assert!(ptr::eq(waker2.vtable(), &WAKER_VTABLE));
}
static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml
index f830808d19648..6d1f9764efbfd 100644
--- a/library/panic_unwind/Cargo.toml
+++ b/library/panic_unwind/Cargo.toml
@@ -20,3 +20,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2", default-features = false }
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+ # #[cfg(bootstrap)] rtems
+ 'cfg(target_os, values("rtems"))',
+]
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 2d174f4b1a4a2..4552fb68d26d5 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -48,7 +48,7 @@ cfg_if::cfg_if! {
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
- all(target_family = "unix", not(target_os = "espidf")),
+ all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems"))),
all(target_vendor = "fortanix", target_env = "sgx"),
target_family = "wasm",
))] {
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 82cfd603a21e3..e20fe9feff114 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -146,4 +146,6 @@ check-cfg = [
# and to the `backtrace` crate which messes-up with Cargo list
# of declared features, we therefor expect any feature cfg
'cfg(feature, values(any()))',
+ # #[cfg(bootstrap)] rtems
+ 'cfg(target_os, values("rtems"))',
]
diff --git a/library/std/build.rs b/library/std/build.rs
index 72254cafc850d..ba1eece46f3ce 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -53,6 +53,7 @@ fn main() {
|| target_os == "uefi"
|| target_os == "teeos"
|| target_os == "zkvm"
+ || target_os == "rtems"
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 918eec2d0d8ef..99bea676e1224 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -852,7 +852,7 @@ impl OsStr {
/// Converts an `OsStr` to a
[Cow]<[str]>
.
///
- /// Any non-Unicode sequences are replaced with
+ /// Any non-UTF-8 sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
/// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 020a8b324f410..a2496baa63fb1 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -143,6 +143,8 @@ pub mod nto;
pub mod openbsd;
#[cfg(target_os = "redox")]
pub mod redox;
+#[cfg(target_os = "rtems")]
+pub mod rtems;
#[cfg(target_os = "solaris")]
pub mod solaris;
#[cfg(target_os = "solid_asp3")]
diff --git a/library/std/src/os/rtems/fs.rs b/library/std/src/os/rtems/fs.rs
new file mode 100644
index 0000000000000..bec0d41e42d81
--- /dev/null
+++ b/library/std/src/os/rtems/fs.rs
@@ -0,0 +1,374 @@
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::rtems::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+
+ fn st_atime_nsec(&self) -> i64 {
+ 0
+ }
+
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+
+ fn st_mtime_nsec(&self) -> i64 {
+ 0
+ }
+
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+
+ fn st_ctime_nsec(&self) -> i64 {
+ 0
+ }
+
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/rtems/mod.rs b/library/std/src/os/rtems/mod.rs
new file mode 100644
index 0000000000000..7275bfd1765d5
--- /dev/null
+++ b/library/std/src/os/rtems/mod.rs
@@ -0,0 +1,4 @@
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![forbid(unsafe_op_in_unsafe_fn)]
+pub mod fs;
+pub(crate) mod raw;
diff --git a/library/std/src/os/rtems/raw.rs b/library/std/src/os/rtems/raw.rs
new file mode 100644
index 0000000000000..113079cf4abdc
--- /dev/null
+++ b/library/std/src/os/rtems/raw.rs
@@ -0,0 +1,33 @@
+//! rtems raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = libc::pthread_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = libc::blkcnt_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = libc::blksize_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = libc::dev_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = libc::ino_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = libc::mode_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = libc::nlink_t;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = libc::off_t;
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = libc::time_t;
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index c6581b9c4c8c8..7d2f0bd4efea7 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -73,6 +73,8 @@ mod platform {
pub use crate::os::openbsd::*;
#[cfg(target_os = "redox")]
pub use crate::os::redox::*;
+ #[cfg(target_os = "rtems")]
+ pub use crate::os::rtems::*;
#[cfg(target_os = "solaris")]
pub use crate::os::solaris::*;
#[cfg(target_os = "vita")]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 9eaa0e01c2c00..506ad445b6bed 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2200,7 +2200,7 @@ impl Path {
/// Converts a `Path` to a [`Cow`].
///
- /// Any non-Unicode sequences are replaced with
+ /// Any non-UTF-8 sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
/// [U+FFFD]: super::char::REPLACEMENT_CHARACTER
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index 9a37e1a0346d7..a943e3a581a83 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -112,6 +112,7 @@ impl DoubleEndedIterator for Args {
target_os = "aix",
target_os = "nto",
target_os = "hurd",
+ target_os = "rtems",
))]
mod imp {
use crate::ffi::c_char;
diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/pal/unix/env.rs
index fb1f868644d48..b2d399b8791b5 100644
--- a/library/std/src/sys/pal/unix/env.rs
+++ b/library/std/src/sys/pal/unix/env.rs
@@ -240,6 +240,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "rtems")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "rtems";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "vxworks")]
pub mod os {
pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index 7fa147c9754b9..4ec577a0a01d0 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -478,6 +478,7 @@ impl FileAttr {
target_os = "horizon",
target_os = "vita",
target_os = "hurd",
+ target_os = "rtems",
)))]
pub fn modified(&self) -> io::Result {
#[cfg(target_pointer_width = "32")]
@@ -490,7 +491,12 @@ impl FileAttr {
SystemTime::new(self.stat.st_mtime as i64, self.stat.st_mtime_nsec as i64)
}
- #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
+ #[cfg(any(
+ target_os = "vxworks",
+ target_os = "espidf",
+ target_os = "vita",
+ target_os = "rtems",
+ ))]
pub fn modified(&self) -> io::Result {
SystemTime::new(self.stat.st_mtime as i64, 0)
}
@@ -506,6 +512,7 @@ impl FileAttr {
target_os = "horizon",
target_os = "vita",
target_os = "hurd",
+ target_os = "rtems",
)))]
pub fn accessed(&self) -> io::Result {
#[cfg(target_pointer_width = "32")]
@@ -518,7 +525,12 @@ impl FileAttr {
SystemTime::new(self.stat.st_atime as i64, self.stat.st_atime_nsec as i64)
}
- #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "vita"))]
+ #[cfg(any(
+ target_os = "vxworks",
+ target_os = "espidf",
+ target_os = "vita",
+ target_os = "rtems"
+ ))]
pub fn accessed(&self) -> io::Result {
SystemTime::new(self.stat.st_atime as i64, 0)
}
@@ -853,6 +865,7 @@ impl Drop for Dir {
target_os = "fuchsia",
target_os = "horizon",
target_os = "vxworks",
+ target_os = "rtems",
)))]
{
let fd = unsafe { libc::dirfd(self.0) };
@@ -970,6 +983,7 @@ impl DirEntry {
target_os = "aix",
target_os = "nto",
target_os = "hurd",
+ target_os = "rtems",
target_vendor = "apple",
))]
pub fn ino(&self) -> u64 {
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index ba2f58f9c10bd..e8428eccb1691 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -79,6 +79,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
target_os = "l4re",
target_os = "horizon",
target_os = "vita",
+ target_os = "rtems",
// The poll on Darwin doesn't set POLLNVAL for closed fds.
target_vendor = "apple",
)))]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index a785b97ac8dc5..503f8915256ee 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -31,7 +31,7 @@ cfg_if::cfg_if! {
}
extern "C" {
- #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
+ #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
#[cfg_attr(
any(
target_os = "linux",
@@ -61,13 +61,14 @@ extern "C" {
}
/// Returns the platform-specific value of errno
-#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
+#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))]
pub fn errno() -> i32 {
unsafe { (*errno_location()) as i32 }
}
/// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
+// needed for readdir and syscall!
+#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))]
#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
@@ -78,6 +79,16 @@ pub fn errno() -> i32 {
unsafe { libc::errnoGet() }
}
+#[cfg(target_os = "rtems")]
+pub fn errno() -> i32 {
+ extern "C" {
+ #[thread_local]
+ static _tls_errno: c_int;
+ }
+
+ unsafe { _tls_errno as i32 }
+}
+
#[cfg(target_os = "dragonfly")]
pub fn errno() -> i32 {
extern "C" {
@@ -472,7 +483,7 @@ pub fn current_exe() -> io::Result {
}
}
-#[cfg(target_os = "redox")]
+#[cfg(any(target_os = "redox", target_os = "rtems"))]
pub fn current_exe() -> io::Result {
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
}
diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs
index 9d091f033e07f..4bb22f3670978 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -1089,13 +1089,13 @@ fn signal_string(signal: i32) -> &'static str {
libc::SIGURG => " (SIGURG)",
#[cfg(not(target_os = "l4re"))]
libc::SIGXCPU => " (SIGXCPU)",
- #[cfg(not(target_os = "l4re"))]
+ #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGXFSZ => " (SIGXFSZ)",
- #[cfg(not(target_os = "l4re"))]
+ #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGVTALRM => " (SIGVTALRM)",
#[cfg(not(target_os = "l4re"))]
libc::SIGPROF => " (SIGPROF)",
- #[cfg(not(target_os = "l4re"))]
+ #[cfg(not(any(target_os = "l4re", target_os = "rtems")))]
libc::SIGWINCH => " (SIGWINCH)",
#[cfg(not(any(target_os = "haiku", target_os = "l4re")))]
libc::SIGIO => " (SIGIO)",
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 272fadd915005..1cc9a2b7ffa98 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -13,7 +13,7 @@ use crate::time::Duration;
#[macro_use]
pub mod compat;
-mod api;
+pub mod api;
pub mod args;
pub mod c;
diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs
index 06eae5a07b068..d40a537e3594a 100644
--- a/library/std/src/sys/pal/windows/process.rs
+++ b/library/std/src/sys/pal/windows/process.rs
@@ -272,11 +272,24 @@ impl Command {
None
};
let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
- // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
- let is_batch_file = matches!(
- program.len().checked_sub(5).and_then(|i| program.get(i..)),
- Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
- );
+ let has_bat_extension = |program: &[u16]| {
+ matches!(
+ // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
+ program.len().checked_sub(4).and_then(|i| program.get(i..)),
+ Some([46, 98 | 66, 97 | 65, 116 | 84] | [46, 99 | 67, 109 | 77, 100 | 68])
+ )
+ };
+ let is_batch_file = if path::is_verbatim(&program) {
+ has_bat_extension(&program[..program.len() - 1])
+ } else {
+ super::fill_utf16_buf(
+ |buffer, size| unsafe {
+ // resolve the path so we can test the final file name.
+ c::GetFullPathNameW(program.as_ptr(), size, buffer, ptr::null_mut())
+ },
+ |program| has_bat_extension(program),
+ )?
+ };
let (program, mut cmd_str) = if is_batch_file {
(
command_prompt()?,
diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs
index 21841eb18cc0e..2ae9a0a91996f 100644
--- a/library/std/src/sys/path/windows.rs
+++ b/library/std/src/sys/path/windows.rs
@@ -1,5 +1,6 @@
use crate::ffi::{OsStr, OsString};
use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::api::utf16;
use crate::sys::pal::{c, fill_utf16_buf, os2path, to_u16s};
use crate::{io, ptr};
@@ -19,6 +20,10 @@ pub fn is_verbatim_sep(b: u8) -> bool {
b == b'\\'
}
+pub fn is_verbatim(path: &[u16]) -> bool {
+ path.starts_with(utf16!(r"\\?\")) || path.starts_with(utf16!(r"\??\"))
+}
+
/// Returns true if `path` looks like a lone filename.
pub(crate) fn is_file_name(path: &OsStr) -> bool {
!path.as_encoded_bytes().iter().copied().any(is_sep_byte)
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 1a6ea1dafcb53..68085d026c40a 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -31,7 +31,7 @@ cfg_if::cfg_if! {
target_os = "psp",
target_os = "xous",
target_os = "solid_asp3",
- all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
+ all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")),
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
mod gcc;
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index bbd1db8dfa57f..590de31a678ca 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -34,3 +34,10 @@ llvm-libunwind = []
# If crt-static is enabled, static link to `libunwind.a` provided by system
# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
system-llvm-libunwind = []
+
+[lints.rust.unexpected_cfgs]
+level = "warn"
+check-cfg = [
+ # #[cfg(bootstrap)] rtems
+ 'cfg(target_os, values("rtems"))',
+]
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 250af912e072d..26ed00bfbd53e 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -22,6 +22,7 @@ cfg_if::cfg_if! {
target_os = "l4re",
target_os = "none",
target_os = "espidf",
+ target_os = "rtems",
))] {
// These "unix" family members do not have unwinder.
} else if #[cfg(any(
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 768aac912ce47..49d564642bd65 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -71,6 +71,7 @@ def v(*args):
# channel, etc.
o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
+o("llvm-enzyme", "llvm.enzyme", "build LLVM with enzyme")
o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
o("debug-assertions-std", "rust.debug-assertions-std", "build the standard library with debugging assertions")
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 7f7faf077d047..ba12e64c4a26f 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -228,7 +228,7 @@ impl Step for Rustc {
self.override_build_kind.unwrap_or(builder.kind),
);
- rustc_cargo(builder, &mut cargo, target, &compiler);
+ rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
// For ./x.py clippy, don't run with --all-targets because
// linting tests and benchmarks can produce very noisy results
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index a2bb03cd5ac81..a0992350722fe 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -197,7 +197,7 @@ impl Step for Rustc {
Kind::Clippy,
);
- rustc_cargo(builder, &mut cargo, target, &compiler);
+ rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
// Explicitly pass -p for all compiler crates -- this will force cargo
// to also lint the tests/benches/examples for these crates, rather
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index eef548033f1c6..1936c91ef83c1 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -931,7 +931,12 @@ impl Step for Rustc {
// NOTE: the ABI of the beta compiler is different from the ABI of the downloaded compiler,
// so its artifacts can't be reused.
if builder.download_rustc() && compiler.stage != 0 {
- builder.ensure(Sysroot { compiler, force_recompile: false });
+ let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
+ cp_rustc_component_to_ci_sysroot(
+ builder,
+ &sysroot,
+ builder.config.ci_rustc_dev_contents(),
+ );
return compiler.stage;
}
@@ -983,7 +988,7 @@ impl Step for Rustc {
Kind::Build,
);
- rustc_cargo(builder, &mut cargo, target, &compiler);
+ rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
// NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be
// consistently applied by check/doc/test modes too.
@@ -1042,10 +1047,11 @@ pub fn rustc_cargo(
cargo: &mut Cargo,
target: TargetSelection,
compiler: &Compiler,
+ crates: &[String],
) {
cargo
.arg("--features")
- .arg(builder.rustc_features(builder.kind, target))
+ .arg(builder.rustc_features(builder.kind, target, crates))
.arg("--manifest-path")
.arg(builder.src.join("compiler/rustc/Cargo.toml"));
@@ -1189,6 +1195,10 @@ pub fn rustc_cargo_env(
cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
}
+ if builder.config.llvm_enzyme {
+ cargo.rustflag("--cfg=llvm_enzyme");
+ }
+
// Note that this is disabled if LLVM itself is disabled or we're in a check
// build. If we are in a check build we still go ahead here presuming we've
// detected that LLVM is already built and good to go which helps prevent
@@ -1784,6 +1794,24 @@ impl Step for Assemble {
// use that to bootstrap this compiler forward.
let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
+ // Build enzyme
+ let enzyme_install = if builder.config.llvm_enzyme {
+ Some(builder.ensure(llvm::Enzyme { target: build_compiler.host }))
+ } else {
+ None
+ };
+
+ if let Some(enzyme_install) = enzyme_install {
+ let lib_ext = std::env::consts::DLL_EXTENSION;
+ let src_lib = enzyme_install.join("build/Enzyme/libEnzyme-19").with_extension(lib_ext);
+ let libdir = builder.sysroot_libdir(build_compiler, build_compiler.host);
+ let target_libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
+ let dst_lib = libdir.join("libEnzyme-19").with_extension(lib_ext);
+ let target_dst_lib = target_libdir.join("libEnzyme-19").with_extension(lib_ext);
+ builder.copy_link(&src_lib, &dst_lib);
+ builder.copy_link(&src_lib, &target_dst_lib);
+ }
+
// Build the libraries for this compiler to link to (i.e., the libraries
// it uses at runtime). NOTE: Crates the target compiler compiles don't
// link to these. (FIXME: Is that correct? It seems to be correct most
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index ffb617c642baf..73d9e3f6793e5 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -826,7 +826,7 @@ impl Step for Rustc {
// see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
// cargo.rustdocflag("--generate-link-to-definition");
- compile::rustc_cargo(builder, &mut cargo, target, &compiler);
+ compile::rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
cargo.arg("-Zskip-rustdoc-fingerprint");
// Only include compiler crates, no dependencies of those, such as `libc`.
@@ -1186,6 +1186,9 @@ impl Step for RustcBook {
cmd.arg("--rustc");
cmd.arg(&rustc);
cmd.arg("--rustc-target").arg(self.target.rustc_target_arg());
+ if let Some(target_linker) = builder.linker(self.target) {
+ cmd.arg("--rustc-linker").arg(target_linker);
+ }
if builder.is_verbose() {
cmd.arg("--verbose");
}
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 8c52df78ab685..91fbc57429a96 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -93,7 +93,6 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result