diff --git a/Cargo.lock b/Cargo.lock
index 7e4db4fdd53e..c034cbae9912 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3824,7 +3824,6 @@ dependencies = [
"rustc_session",
"rustc_smir",
"rustc_span",
- "rustc_symbol_mangling",
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
@@ -4008,7 +4007,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
- "rustc_graphviz",
"rustc_hir",
"rustc_hir_analysis",
"rustc_hir_pretty",
@@ -4468,7 +4466,6 @@ dependencies = [
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
- "rustc_hir_analysis",
"rustc_macros",
"rustc_middle",
"rustc_session",
@@ -4515,7 +4512,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
- "rustc_type_ir",
"smallvec",
"thin-vec",
"tracing",
diff --git a/RELEASES.md b/RELEASES.md
index 104ea497ba49..3080f03c7210 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -102,6 +102,10 @@ Compatibility Notes
- [Change equality of higher ranked types to not rely on subtyping](https://github.com/rust-lang/rust/pull/118247)
- [When called, additionally check bounds on normalized function return type](https://github.com/rust-lang/rust/pull/118882)
- [Expand coverage for `arithmetic_overflow` lint](https://github.com/rust-lang/rust/pull/119432/)
+- [Fix detection of potential interior mutability in `const` initializers](https://github.com/rust-lang/rust/issues/121250)
+ This code was accidentally accepted. The fix can break generic code that borrows a value of unknown type,
+ as there is currently no way to declare "this type has no interior mutability". In the future, stabilizing
+ the [`Freeze` trait](https://github.com/rust-lang/rust/issues/121675) will allow proper support for such code.
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs
index 434b978ae315..7ba58406ef1a 100644
--- a/compiler/rustc/src/main.rs
+++ b/compiler/rustc/src/main.rs
@@ -1,5 +1,3 @@
-#![feature(unix_sigpipe)]
-
// A note about jemalloc: rustc uses jemalloc when built for CI and
// distribution. The obvious way to do this is with the `#[global_allocator]`
// mechanism. However, for complicated reasons (see
@@ -34,7 +32,6 @@
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
// for an example of how to do so.
-#[unix_sigpipe = "sig_dfl"]
fn main() {
// See the comment at the top of this file for an explanation of this.
#[cfg(feature = "jemalloc-sys")]
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 6a2943da4a3f..5e3f64540e4a 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -21,6 +21,8 @@ use rustc_macros::{Decodable_Generic, Encodable_Generic};
use std::iter::Step;
mod layout;
+#[cfg(test)]
+mod tests;
pub use layout::LayoutCalculator;
diff --git a/compiler/rustc_abi/src/tests.rs b/compiler/rustc_abi/src/tests.rs
new file mode 100644
index 000000000000..d993012378c8
--- /dev/null
+++ b/compiler/rustc_abi/src/tests.rs
@@ -0,0 +1,7 @@
+use super::*;
+
+#[test]
+fn align_constants() {
+ assert_eq!(Align::ONE, Align::from_bytes(1).unwrap());
+ assert_eq!(Align::EIGHT, Align::from_bytes(8).unwrap());
+}
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index be6c7da4108c..7254be2b2f42 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -62,7 +62,7 @@ pub(super) fn index_hir<'hir>(
if let Node::Err(span) = node.node {
let hir_id = HirId { owner: item.def_id(), local_id };
let msg = format!("ID {hir_id} not encountered when visiting item HIR");
- tcx.dcx().span_delayed_bug(*span, msg);
+ tcx.dcx().span_delayed_bug(span, msg);
}
}
@@ -376,7 +376,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}
}
- fn visit_array_length(&mut self, len: &'hir ArrayLen) {
+ fn visit_array_length(&mut self, len: &'hir ArrayLen<'hir>) {
match len {
ArrayLen::Infer(inf) => self.insert(inf.span, inf.hir_id, Node::ArrayLenInfer(inf)),
ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index dcd8f5d5f150..156e369c4585 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1589,11 +1589,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
- default: Some(hir::AnonConst {
+ default: Some(self.arena.alloc(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
body: const_body,
- }),
+ span,
+ })),
is_host_effect: true,
},
colon_span: None,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dd8c09ce485e..6c54363e306d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1178,14 +1178,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
tokens: None,
};
- let ct = self.with_new_scopes(span, |this| hir::AnonConst {
- def_id,
- hir_id: this.lower_node_id(node_id),
- body: this.lower_const_body(path_expr.span, Some(&path_expr)),
+ let ct = self.with_new_scopes(span, |this| {
+ self.arena.alloc(hir::AnonConst {
+ def_id,
+ hir_id: this.lower_node_id(node_id),
+ body: this
+ .lower_const_body(path_expr.span, Some(&path_expr)),
+ span,
+ })
});
return GenericArg::Const(ConstArg {
value: ct,
- span,
is_desugared_from_effects: false,
});
}
@@ -1197,7 +1200,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(ct),
- span: self.lower_span(ct.value.span),
is_desugared_from_effects: false,
}),
}
@@ -2315,7 +2317,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
- fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+ fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen<'hir> {
match c.value.kind {
ExprKind::Underscore => {
if self.tcx.features().generic_arg_infer {
@@ -2338,12 +2340,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
- fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
- self.with_new_scopes(c.value.span, |this| hir::AnonConst {
+ fn lower_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
+ self.arena.alloc(self.with_new_scopes(c.value.span, |this| hir::AnonConst {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
- })
+ span: this.lower_span(c.value.span),
+ }))
}
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
@@ -2650,8 +2653,7 @@ impl<'hir> GenericArgsCtor<'hir> {
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.args.push(hir::GenericArg::Const(hir::ConstArg {
- value: hir::AnonConst { def_id, hir_id, body },
- span,
+ value: lcx.arena.alloc(hir::AnonConst { def_id, hir_id, body, span }),
is_desugared_from_effects: true,
}))
}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2c717661a1c4..2450ac8f4b33 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -307,7 +307,7 @@ fn make_format_args(
return ExpandResult::Ready(Err(guar));
}
- let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+ let to_span = |inner_span: parse::InnerSpan| {
is_source_literal.then(|| {
fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
})
@@ -577,7 +577,7 @@ fn make_format_args(
fn invalid_placeholder_type_error(
ecx: &ExtCtxt<'_>,
ty: &str,
- ty_span: Option,
+ ty_span: Option,
fmt_span: Span,
) {
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 16a85b4e8fa0..4a1f5188a801 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -6,7 +6,8 @@ use gccjit::{
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, MiscMethods};
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::span_bug;
@@ -621,7 +622,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push_str(".");
- base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+ name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
name
}
}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5c8f358d03a1..1a1b4ae38313 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -17,7 +17,7 @@ use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
- FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout,
+ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_sanitizers::{cfi, kcfi};
@@ -27,7 +27,6 @@ use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
use smallvec::SmallVec;
use std::borrow::Cow;
-use std::ffi::CString;
use std::iter;
use std::ops::Deref;
use std::ptr;
@@ -1705,13 +1704,21 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
kcfi_bundle
}
+ /// Emits a call to `llvm.instrprof.mcdc.parameters`.
+ ///
+ /// This doesn't produce any code directly, but is used as input by
+ /// the LLVM pass that handles coverage instrumentation.
+ ///
+ /// (See clang's [`CodeGenPGO::emitMCDCParameters`] for comparison.)
+ ///
+ /// [`CodeGenPGO::emitMCDCParameters`]:
+ /// https://github.com/rust-lang/llvm-project/blob/5399a24/clang/lib/CodeGen/CodeGenPGO.cpp#L1124
pub(crate) fn mcdc_parameters(
&mut self,
fn_name: &'ll Value,
hash: &'ll Value,
bitmap_bytes: &'ll Value,
- max_decision_depth: u32,
- ) -> Vec<&'ll Value> {
+ ) {
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes);
assert!(llvm_util::get_version() >= (18, 0, 0), "MCDC intrinsics require LLVM 18 or later");
@@ -1724,8 +1731,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
let args = &[fn_name, hash, bitmap_bytes];
let args = self.check_call("call", llty, llfn, args);
- let mut cond_bitmaps = vec![];
-
unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
@@ -1736,23 +1741,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
[].as_ptr(),
0 as c_uint,
);
- // Create condition bitmap named `mcdc.addr`.
- for i in 0..=max_decision_depth {
- let mut bx = Builder::with_cx(self.cx);
- bx.position_at_start(llvm::LLVMGetFirstBasicBlock(self.llfn()));
-
- let name = CString::new(format!("mcdc.addr.{i}")).unwrap();
- let cond_bitmap = {
- let alloca =
- llvm::LLVMBuildAlloca(bx.llbuilder, bx.cx.type_i32(), name.as_ptr());
- llvm::LLVMSetAlignment(alloca, 4);
- alloca
- };
- bx.store(self.const_i32(0), cond_bitmap, self.tcx().data_layout.i32_align.abi);
- cond_bitmaps.push(cond_bitmap);
- }
}
- cond_bitmaps
}
pub(crate) fn mcdc_tvbitmap_update(
@@ -1794,8 +1783,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
0 as c_uint,
);
}
- let i32_align = self.tcx().data_layout.i32_align.abi;
- self.store(self.const_i32(0), mcdc_temp, i32_align);
+ self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
}
pub(crate) fn mcdc_condbitmap_update(
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index d32baa6dc02a..653abb4e41b3 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -11,7 +11,8 @@ use crate::value::Value;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::errors as ssa_errors;
use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
@@ -1015,7 +1016,7 @@ impl CodegenCx<'_, '_> {
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push('.');
- base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
+ name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
name
}
}
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 679c6e1a2ff8..c51a7744a30a 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -13,10 +13,10 @@ use rustc_codegen_ssa::traits::{
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_llvm::RustString;
use rustc_middle::bug;
-use rustc_middle::mir::coverage::{CoverageKind, FunctionCoverageInfo};
+use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Instance;
-use rustc_target::abi::Align;
+use rustc_target::abi::{Align, Size};
use std::cell::RefCell;
@@ -91,6 +91,42 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
}
impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
+ fn init_coverage(&mut self, instance: Instance<'tcx>) {
+ let Some(function_coverage_info) =
+ self.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
+ else {
+ return;
+ };
+
+ // If there are no MC/DC bitmaps to set up, return immediately.
+ if function_coverage_info.mcdc_bitmap_bytes == 0 {
+ return;
+ }
+
+ let fn_name = self.get_pgo_func_name_var(instance);
+ let hash = self.const_u64(function_coverage_info.function_source_hash);
+ let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes);
+ self.mcdc_parameters(fn_name, hash, bitmap_bytes);
+
+ // Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
+ let mut cond_bitmaps = vec![];
+ for i in 0..function_coverage_info.mcdc_num_condition_bitmaps {
+ // MC/DC intrinsics will perform loads/stores that use the ABI default
+ // alignment for i32, so our variable declaration should match.
+ let align = self.tcx.data_layout.i32_align.abi;
+ let cond_bitmap = self.alloca(Size::from_bytes(4), align);
+ llvm::set_value_name(cond_bitmap, format!("mcdc.addr.{i}").as_bytes());
+ self.store(self.const_i32(0), cond_bitmap, align);
+ cond_bitmaps.push(cond_bitmap);
+ }
+
+ self.coverage_context()
+ .expect("always present when coverage is enabled")
+ .mcdc_condition_bitmap_map
+ .borrow_mut()
+ .insert(instance, cond_bitmaps);
+ }
+
#[instrument(level = "debug", skip(self))]
fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
// Our caller should have already taken care of inlining subtleties,
@@ -109,10 +145,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
return;
};
- if function_coverage_info.mcdc_bitmap_bytes > 0 {
- ensure_mcdc_parameters(bx, instance, function_coverage_info);
- }
-
let Some(coverage_context) = bx.coverage_context() else { return };
let mut coverage_map = coverage_context.function_coverage_map.borrow_mut();
let func_coverage = coverage_map
@@ -193,28 +225,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
}
}
-fn ensure_mcdc_parameters<'ll, 'tcx>(
- bx: &mut Builder<'_, 'll, 'tcx>,
- instance: Instance<'tcx>,
- function_coverage_info: &FunctionCoverageInfo,
-) {
- let Some(cx) = bx.coverage_context() else { return };
- if cx.mcdc_condition_bitmap_map.borrow().contains_key(&instance) {
- return;
- }
-
- let fn_name = bx.get_pgo_func_name_var(instance);
- let hash = bx.const_u64(function_coverage_info.function_source_hash);
- let bitmap_bytes = bx.const_u32(function_coverage_info.mcdc_bitmap_bytes);
- let max_decision_depth = function_coverage_info.mcdc_max_decision_depth;
- let cond_bitmap = bx.mcdc_parameters(fn_name, hash, bitmap_bytes, max_decision_depth as u32);
- bx.coverage_context()
- .expect("already checked above")
- .mcdc_condition_bitmap_map
- .borrow_mut()
- .insert(instance, cond_bitmap);
-}
-
/// Calls llvm::createPGOFuncNameVar() with the given function instance's
/// mangled function name. The LLVM API returns an llvm::GlobalVariable
/// containing the function name, with the specific variable name and linkage
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 0064c16f5d9f..cf6e2e8d14c6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -259,6 +259,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx);
+ // If the backend supports coverage, and coverage is enabled for this function,
+ // do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
+ start_bx.init_coverage(instance);
+
// The builders will be created separately for each basic block at `codegen_block`.
// So drop the builder of `start_llbb` to avoid having two at the same time.
drop(start_bx);
diff --git a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
index d1d813bd3892..906d8b87d3bc 100644
--- a/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
@@ -3,6 +3,11 @@ use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
+ /// Performs any start-of-function codegen needed for coverage instrumentation.
+ ///
+ /// Can be a no-op in backends that don't support coverage instrumentation.
+ fn init_coverage(&mut self, _instance: Instance<'tcx>) {}
+
/// Handle the MIR coverage info in a backend-specific way.
///
/// This can potentially be a no-op in backends that don't support
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index 7b6828c6e182..afc60d33647a 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -105,7 +105,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
_target: Option,
_unwind: UnwindAction,
- ) -> interpret::InterpResult<'tcx> {
+ ) -> interpret::InterpResult<'tcx, Option>> {
unimplemented!()
}
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index dd835279df33..e9cf5a3d7697 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -459,16 +459,26 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
dest: &MPlaceTy<'tcx, Self::Provenance>,
target: Option,
_unwind: mir::UnwindAction,
- ) -> InterpResult<'tcx> {
+ ) -> InterpResult<'tcx, Option>> {
// Shared intrinsics.
if ecx.emulate_intrinsic(instance, args, dest, target)? {
- return Ok(());
+ return Ok(None);
}
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
// CTFE-specific intrinsics.
let Some(ret) = target else {
- throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
+ // Handle diverging intrinsics. We can't handle any of them (that are not already
+ // handled above), but check if there is a fallback body.
+ if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
+ throw_unsup_format!(
+ "intrinsic `{intrinsic_name}` is not supported at compile-time"
+ );
+ }
+ return Ok(Some(ty::Instance {
+ def: ty::InstanceDef::Item(instance.def_id()),
+ args: instance.args,
+ }));
};
match intrinsic_name {
sym::ptr_guaranteed_cmp => {
@@ -536,14 +546,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
// not the optimization stage.)
sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?,
_ => {
- throw_unsup_format!(
- "intrinsic `{intrinsic_name}` is not supported at compile-time"
- );
+ // We haven't handled the intrinsic, let's see if we can use a fallback body.
+ if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden {
+ throw_unsup_format!(
+ "intrinsic `{intrinsic_name}` is not supported at compile-time"
+ );
+ }
+ return Ok(Some(ty::Instance {
+ def: ty::InstanceDef::Item(instance.def_id()),
+ args: instance.args,
+ }));
}
}
ecx.go_to_block(ret);
- Ok(())
+ Ok(None)
}
fn assert_panic(
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4d37c3c22cd7..f73293856c7e 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -414,7 +414,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
self.copy_op(&self.project_index(&input, index)?, dest)?;
}
- sym::likely | sym::unlikely | sym::black_box => {
+ sym::black_box => {
// These just return their argument
self.copy_op(&args[0], dest)?;
}
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 8bc569bed54c..8405d0746dfd 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -216,6 +216,9 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Directly process an intrinsic without pushing a stack frame. It is the hook's
/// responsibility to advance the instruction pointer as appropriate.
+ ///
+ /// Returns `None` if the intrinsic was fully handled.
+ /// Otherwise, returns an `Instance` of the function that implements the intrinsic.
fn call_intrinsic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
@@ -223,7 +226,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
destination: &MPlaceTy<'tcx, Self::Provenance>,
target: Option,
unwind: mir::UnwindAction,
- ) -> InterpResult<'tcx>;
+ ) -> InterpResult<'tcx, Option>>;
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
fn assert_panic(
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 9c31532a9ce4..07425f9a6865 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -539,14 +539,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::InstanceDef::Intrinsic(def_id) => {
assert!(self.tcx.intrinsic(def_id).is_some());
// FIXME: Should `InPlace` arguments be reset to uninit?
- M::call_intrinsic(
+ if let Some(fallback) = M::call_intrinsic(
self,
instance,
&self.copy_fn_args(args),
destination,
target,
unwind,
- )
+ )? {
+ assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden);
+ assert!(matches!(fallback.def, ty::InstanceDef::Item(_)));
+ return self.eval_fn_call(
+ FnVal::Instance(fallback),
+ (caller_abi, caller_fn_abi),
+ args,
+ with_caller_location,
+ destination,
+ target,
+ unwind,
+ );
+ } else {
+ Ok(())
+ }
}
ty::InstanceDef::VTableShim(..)
| ty::InstanceDef::ReifyShim(..)
diff --git a/compiler/rustc_data_structures/src/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs
index a3eb2b9c416f..aed89fadc4c8 100644
--- a/compiler/rustc_data_structures/src/base_n.rs
+++ b/compiler/rustc_data_structures/src/base_n.rs
@@ -1,6 +1,7 @@
/// Converts unsigned integers into a string representation with some base.
/// Bases up to and including 36 can be used for case-insensitive things.
-use std::str;
+use std::ascii;
+use std::fmt;
#[cfg(test)]
mod tests;
@@ -9,36 +10,101 @@ pub const MAX_BASE: usize = 64;
pub const ALPHANUMERIC_ONLY: usize = 62;
pub const CASE_INSENSITIVE: usize = 36;
-const BASE_64: &[u8; MAX_BASE] =
- b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
+const BASE_64: [ascii::Char; MAX_BASE] = {
+ let bytes = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
+ let Some(ascii) = bytes.as_ascii() else { panic!() };
+ *ascii
+};
-#[inline]
-pub fn push_str(mut n: u128, base: usize, output: &mut String) {
- debug_assert!(base >= 2 && base <= MAX_BASE);
- let mut s = [0u8; 128];
- let mut index = s.len();
+pub struct BaseNString {
+ start: usize,
+ buf: [ascii::Char; 128],
+}
- let base = base as u128;
+impl std::ops::Deref for BaseNString {
+ type Target = str;
- loop {
- index -= 1;
- s[index] = BASE_64[(n % base) as usize];
- n /= base;
+ fn deref(&self) -> &str {
+ self.buf[self.start..].as_str()
+ }
+}
- if n == 0 {
- break;
- }
+impl AsRef for BaseNString {
+ fn as_ref(&self) -> &str {
+ self.buf[self.start..].as_str()
+ }
+}
+
+impl fmt::Display for BaseNString {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self)
+ }
+}
+
+// This trait just lets us reserve the exact right amount of space when doing fixed-length
+// case-insensitve encoding. Add any impls you need.
+pub trait ToBaseN: Into {
+ fn encoded_len(base: usize) -> usize;
+
+ fn to_base_fixed_len(self, base: usize) -> BaseNString {
+ let mut encoded = self.to_base(base);
+ encoded.start = encoded.buf.len() - Self::encoded_len(base);
+ encoded
}
- output.push_str(unsafe {
- // SAFETY: `s` is populated using only valid utf8 characters from `BASE_64`
- str::from_utf8_unchecked(&s[index..])
- });
+ fn to_base(self, base: usize) -> BaseNString {
+ let mut output = [ascii::Char::Digit0; 128];
+
+ let mut n: u128 = self.into();
+
+ let mut index = output.len();
+ loop {
+ index -= 1;
+ output[index] = BASE_64[(n % base as u128) as usize];
+ n /= base as u128;
+
+ if n == 0 {
+ break;
+ }
+ }
+ assert_eq!(n, 0);
+
+ BaseNString { start: index, buf: output }
+ }
}
-#[inline]
-pub fn encode(n: u128, base: usize) -> String {
- let mut s = String::new();
- push_str(n, base, &mut s);
- s
+impl ToBaseN for u128 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u128::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u128;
+ }
+ len
+ }
+}
+
+impl ToBaseN for u64 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u64::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u64;
+ }
+ len
+ }
+}
+
+impl ToBaseN for u32 {
+ fn encoded_len(base: usize) -> usize {
+ let mut max = u32::MAX;
+ let mut len = 0;
+ while max > 0 {
+ len += 1;
+ max /= base as u32;
+ }
+ len
+ }
}
diff --git a/compiler/rustc_data_structures/src/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs
index 2be2f0532c99..148d8dde02af 100644
--- a/compiler/rustc_data_structures/src/base_n/tests.rs
+++ b/compiler/rustc_data_structures/src/base_n/tests.rs
@@ -1,9 +1,17 @@
use super::*;
#[test]
-fn test_encode() {
+fn limits() {
+ assert_eq!(Ok(u128::MAX), u128::from_str_radix(&u128::MAX.to_base(36), 36));
+ assert_eq!(Ok(u64::MAX), u64::from_str_radix(&u64::MAX.to_base(36), 36));
+ assert_eq!(Ok(u32::MAX), u32::from_str_radix(&u32::MAX.to_base(36), 36));
+}
+
+#[test]
+fn test_to_base() {
fn test(n: u128, base: usize) {
- assert_eq!(Ok(n), u128::from_str_radix(&encode(n, base), base as u32));
+ assert_eq!(Ok(n), u128::from_str_radix(&n.to_base(base), base as u32));
+ assert_eq!(Ok(n), u128::from_str_radix(&n.to_base_fixed_len(base), base as u32));
}
for base in 2..37 {
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index cf54e700e2b9..8dd85b25e0e2 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -16,6 +16,8 @@
#![doc(rust_logo)]
#![feature(allocator_api)]
#![feature(array_windows)]
+#![feature(ascii_char)]
+#![feature(ascii_char_variants)]
#![feature(auto_traits)]
#![feature(cfg_match)]
#![feature(core_intrinsics)]
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index a8bba3afb7e7..cb37644d570d 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -42,9 +42,8 @@ rustc_privacy = { path = "../rustc_privacy" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_session = { path = "../rustc_session" }
-rustc_smir ={ path = "../rustc_smir" }
+rustc_smir = { path = "../rustc_smir" }
rustc_span = { path = "../rustc_span" }
-rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index b3a1e29f8e2c..4696917554ff 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -13,7 +13,7 @@ use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_span::Span;
use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
-use rustc_type_ir as type_ir;
+use rustc_type_ir::{ClosureKind, FloatTy};
use std::backtrace::Backtrace;
use std::borrow::Cow;
use std::fmt;
@@ -196,7 +196,7 @@ impl IntoDiagArg for ast::token::TokenKind {
}
}
-impl IntoDiagArg for type_ir::FloatTy {
+impl IntoDiagArg for FloatTy {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(Cow::Borrowed(self.name_str()))
}
@@ -252,7 +252,7 @@ impl IntoDiagArg for Level {
}
}
-impl IntoDiagArg for type_ir::ClosureKind {
+impl IntoDiagArg for ClosureKind {
fn into_diag_arg(self) -> DiagArgValue {
DiagArgValue::Str(self.as_str().into())
}
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 9d3aac66c410..9c33cc8ed0b9 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -396,10 +396,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// Entry point:
- gated!(
- unix_sigpipe, Normal, template!(NameValueStr: "inherit|sig_ign|sig_dfl"), ErrorFollowing,
- EncodeCrossCrate::Yes, experimental!(unix_sigpipe)
- ),
ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index e7d7a9f380b1..fe50499db767 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -619,8 +619,6 @@ declare_features! (
/// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528)
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
- /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
- (unstable, unix_sigpipe, "1.65.0", Some(97889)),
/// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
/// Allows unsized fn parameters.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index fc8f7466694c..244c479120dc 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -229,9 +229,8 @@ impl<'hir> PathSegment<'hir> {
}
#[derive(Clone, Copy, Debug, HashStable_Generic)]
-pub struct ConstArg {
- pub value: AnonConst,
- pub span: Span,
+pub struct ConstArg<'hir> {
+ pub value: &'hir AnonConst,
/// Indicates whether this comes from a `~const` desugaring.
pub is_desugared_from_effects: bool,
}
@@ -252,7 +251,7 @@ impl InferArg {
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
- Const(ConstArg),
+ Const(ConstArg<'hir>),
Infer(InferArg),
}
@@ -261,7 +260,7 @@ impl GenericArg<'_> {
match self {
GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
- GenericArg::Const(c) => c.span,
+ GenericArg::Const(c) => c.value.span,
GenericArg::Infer(i) => i.span,
}
}
@@ -490,7 +489,7 @@ pub enum GenericParamKind<'hir> {
Const {
ty: &'hir Ty<'hir>,
/// Optional default value for the const generic param
- default: Option,
+ default: Option<&'hir AnonConst>,
is_host_effect: bool,
},
}
@@ -1562,12 +1561,12 @@ impl fmt::Display for ConstContext {
pub type Lit = Spanned;
#[derive(Copy, Clone, Debug, HashStable_Generic)]
-pub enum ArrayLen {
+pub enum ArrayLen<'hir> {
Infer(InferArg),
- Body(AnonConst),
+ Body(&'hir AnonConst),
}
-impl ArrayLen {
+impl ArrayLen<'_> {
pub fn hir_id(&self) -> HirId {
match self {
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
@@ -1590,6 +1589,7 @@ pub struct AnonConst {
pub hir_id: HirId,
pub def_id: LocalDefId,
pub body: BodyId,
+ pub span: Span,
}
/// An inline constant expression `const { something }`.
@@ -2002,7 +2002,7 @@ pub enum ExprKind<'hir> {
///
/// E.g., `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- Repeat(&'hir Expr<'hir>, ArrayLen),
+ Repeat(&'hir Expr<'hir>, ArrayLen<'hir>),
/// A suspension point for coroutines (i.e., `yield `).
Yield(&'hir Expr<'hir>, YieldSource),
@@ -2382,7 +2382,7 @@ pub struct TypeBinding<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Term<'hir> {
Ty(&'hir Ty<'hir>),
- Const(AnonConst),
+ Const(&'hir AnonConst),
}
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
@@ -2391,8 +2391,8 @@ impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
}
}
-impl<'hir> From for Term<'hir> {
- fn from(c: AnonConst) -> Self {
+impl<'hir> From<&'hir AnonConst> for Term<'hir> {
+ fn from(c: &'hir AnonConst) -> Self {
Term::Const(c)
}
}
@@ -2683,7 +2683,7 @@ pub enum TyKind<'hir> {
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
/// A fixed length array (i.e., `[T; n]`).
- Array(&'hir Ty<'hir>, ArrayLen),
+ Array(&'hir Ty<'hir>, ArrayLen<'hir>),
/// A raw pointer (i.e., `*const T` or `*mut T`).
Ptr(MutTy<'hir>),
/// A reference (i.e., `&'a T` or `&'a mut T`).
@@ -2712,7 +2712,7 @@ pub enum TyKind<'hir> {
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
/// Unused for now.
- Typeof(AnonConst),
+ Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
Infer,
@@ -2745,10 +2745,10 @@ pub enum InlineAsmOperand<'hir> {
out_expr: Option<&'hir Expr<'hir>>,
},
Const {
- anon_const: AnonConst,
+ anon_const: &'hir AnonConst,
},
SymFn {
- anon_const: AnonConst,
+ anon_const: &'hir AnonConst,
},
SymStatic {
path: QPath<'hir>,
@@ -2950,7 +2950,7 @@ pub struct Variant<'hir> {
/// Fields and constructor id of the variant.
pub data: VariantData<'hir>,
/// Explicit discriminant (e.g., `Foo = 1`).
- pub disr_expr: Option,
+ pub disr_expr: Option<&'hir AnonConst>,
/// Span
pub span: Span,
}
@@ -3479,15 +3479,13 @@ impl<'hir> OwnerNode<'hir> {
}
}
- // Span by reference to pass to `Node::Err`.
- #[allow(rustc::pass_by_value)]
- pub fn span(&self) -> &'hir Span {
+ pub fn span(&self) -> Span {
match self {
OwnerNode::Item(Item { span, .. })
| OwnerNode::ForeignItem(ForeignItem { span, .. })
| OwnerNode::ImplItem(ImplItem { span, .. })
- | OwnerNode::TraitItem(TraitItem { span, .. }) => span,
- OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => inner_span,
+ | OwnerNode::TraitItem(TraitItem { span, .. }) => *span,
+ OwnerNode::Crate(Mod { spans: ModSpans { inner_span, .. }, .. }) => *inner_span,
OwnerNode::Synthetic => unreachable!(),
}
}
@@ -3632,9 +3630,7 @@ pub enum Node<'hir> {
PreciseCapturingNonLifetimeArg(&'hir PreciseCapturingNonLifetimeArg),
// Created by query feeding
Synthetic,
- // Span by reference to minimize `Node`'s size
- #[allow(rustc::pass_by_value)]
- Err(&'hir Span),
+ Err(Span),
}
impl<'hir> Node<'hir> {
@@ -3871,7 +3867,7 @@ mod size_asserts {
static_assert_size!(FnDecl<'_>, 40);
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
- static_assert_size!(GenericArg<'_>, 32);
+ static_assert_size!(GenericArg<'_>, 24);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index cd9f9ff9109c..fa89a4a44ef5 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -338,7 +338,7 @@ pub trait Visitor<'v>: Sized {
fn visit_pat_field(&mut self, f: &'v PatField<'v>) -> Self::Result {
walk_pat_field(self, f)
}
- fn visit_array_length(&mut self, len: &'v ArrayLen) -> Self::Result {
+ fn visit_array_length(&mut self, len: &'v ArrayLen<'v>) -> Self::Result {
walk_array_len(self, len)
}
fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
@@ -703,7 +703,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
visitor.visit_pat(field.pat)
}
-pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) -> V::Result {
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>) -> V::Result {
match len {
// FIXME: Use `visit_infer` here.
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index aafb5c1c0b4b..5562b81871fc 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -23,7 +23,7 @@ use rustc_span::Span;
/// include the self type (e.g., `trait_bounds`) but in others we do not
#[derive(Default, PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
- pub clauses: Vec<(ty::Clause<'tcx>, Span)>,
+ clauses: Vec<(ty::Clause<'tcx>, Span)>,
}
impl<'tcx> Bounds<'tcx> {
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0f0736f87568..9198ceb8f59d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -143,7 +143,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector {
_ => {}
}
}
- fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
+ fn visit_array_length(&mut self, length: &'v hir::ArrayLen<'v>) {
if let hir::ArrayLen::Infer(inf) = length {
self.0.push(inf.span);
}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 9d7deebac48e..5ccfd06f2582 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -24,7 +24,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let node = tcx.hir_node(hir_id);
- let Node::AnonConst(_) = node else {
+ let Node::AnonConst(&AnonConst { span, .. }) = node else {
span_bug!(
tcx.def_span(def_id),
"expected anon const in `anon_const_type_of`, got {node:?}"
@@ -134,7 +134,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
"unexpected non-GAT usage of an anon const",
);
}
@@ -152,7 +152,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unable to find type-dependent def for {parent_node_id:?}"),
);
};
@@ -194,7 +194,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
} else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
);
}
@@ -202,7 +202,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected const parent path {parent_node:?}"),
);
}
@@ -226,11 +226,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.map(|idx| (idx, seg))
})
}) else {
- return Ty::new_error_with_message(
- tcx,
- tcx.def_span(def_id),
- "no arg matching AnonConst in path",
- );
+ return Ty::new_error_with_message(tcx, span, "no arg matching AnonConst in path");
};
let generics = match tcx.res_generics_def_id(segment.res) {
@@ -238,7 +234,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
None => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
);
}
@@ -250,7 +246,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
_ => {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("unexpected const parent in type_of(): {parent_node:?}"),
);
}
@@ -278,7 +274,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
} else {
return Ty::new_error_with_message(
tcx,
- tcx.def_span(def_id),
+ span,
format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"),
);
}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 285b99c2c69d..4f5fbd024a99 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -968,7 +968,7 @@ impl<'a> State<'a> {
self.print_else(elseopt)
}
- fn print_array_length(&mut self, len: &hir::ArrayLen) {
+ fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
match len {
hir::ArrayLen::Infer(..) => self.word("_"),
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
@@ -1052,7 +1052,7 @@ impl<'a> State<'a> {
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
+ fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen<'_>) {
self.ibox(INDENT_UNIT);
self.word("[");
self.print_expr(element);
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index 9e7f0776b608..73a775690d66 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -12,7 +12,6 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 8b1ea7c952cb..7b552bb70774 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1444,7 +1444,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
- && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
+ && let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length
{
let span = self.tcx.hir().span(hir_id);
self.dcx().try_steal_modify_and_emit_err(
@@ -1483,7 +1483,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
- count: &'tcx hir::ArrayLen,
+ count: &'tcx hir::ArrayLen<'tcx>,
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 2060e08aacf9..552747bdc527 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- pub fn lower_array_length(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
+ pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
match length {
hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span),
hir::ArrayLen::Body(anon_const) => {
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 382dba5f95fb..8c7ae7f8e980 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -10,7 +10,6 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::TypeVariableOrigin;
-use rustc_lint as lint;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
@@ -684,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
// `mut x` resets the binding mode in edition <= 2021.
self.tcx.emit_node_span_lint(
- lint::builtin::DEREFERENCING_MUT_BINDING,
+ rustc_lint::builtin::DEREFERENCING_MUT_BINDING,
pat.hir_id,
pat.span,
errors::DereferencingMutBinding { span: pat.span },
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 3d7c0cfc30aa..193042b8cdf2 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -104,10 +104,14 @@
//! implemented.
use crate::errors;
+use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::BaseNString;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::CASE_INSENSITIVE;
+use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_data_structures::{base_n, flock};
use rustc_errors::ErrorGuaranteed;
use rustc_fs_util::{link_or_copy, try_canonicalize, LinkOrCopy};
use rustc_middle::bug;
@@ -333,31 +337,24 @@ pub fn finalize_session_directory(sess: &Session, svh: Option) {
debug!("finalize_session_directory() - session directory: {}", incr_comp_session_dir.display());
- let old_sub_dir_name = incr_comp_session_dir
+ let mut sub_dir_name = incr_comp_session_dir
.file_name()
.unwrap()
.to_str()
- .expect("malformed session dir name: contains non-Unicode characters");
+ .expect("malformed session dir name: contains non-Unicode characters")
+ .to_string();
- // Keep the 's-{timestamp}-{random-number}' prefix, but replace the
- // '-working' part with the SVH of the crate
- let dash_indices: Vec<_> = old_sub_dir_name.match_indices('-').map(|(idx, _)| idx).collect();
- if dash_indices.len() != 3 {
- bug!(
- "Encountered incremental compilation session directory with \
- malformed name: {}",
- incr_comp_session_dir.display()
- )
- }
+ // Keep the 's-{timestamp}-{random-number}' prefix, but replace "working" with the SVH of the crate
+ sub_dir_name.truncate(sub_dir_name.len() - "working".len());
+ // Double-check that we kept this: "s-{timestamp}-{random-number}-"
+ assert!(sub_dir_name.ends_with('-'), "{:?}", sub_dir_name);
+ assert!(sub_dir_name.as_bytes().iter().filter(|b| **b == b'-').count() == 3);
- // State: "s-{timestamp}-{random-number}-"
- let mut new_sub_dir_name = String::from(&old_sub_dir_name[..=dash_indices[2]]);
-
- // Append the svh
- base_n::push_str(svh.as_u128(), INT_ENCODE_BASE, &mut new_sub_dir_name);
+ // Append the SVH
+ sub_dir_name.push_str(&svh.as_u128().to_base_fixed_len(CASE_INSENSITIVE));
// Create the full path
- let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name);
+ let new_path = incr_comp_session_dir.parent().unwrap().join(&*sub_dir_name);
debug!("finalize_session_directory() - new path: {}", new_path.display());
match rename_path_with_retry(&*incr_comp_session_dir, &new_path, 3) {
@@ -453,11 +450,11 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
let random_number = thread_rng().next_u32();
debug!("generate_session_dir_path: random_number = {}", random_number);
- let directory_name = format!(
- "s-{}-{}-working",
- timestamp,
- base_n::encode(random_number as u128, INT_ENCODE_BASE)
- );
+ // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while.
+ let (zeroes, timestamp) = timestamp.split_at(3);
+ assert_eq!(zeroes, "000");
+ let directory_name =
+ format!("s-{}-{}-working", timestamp, random_number.to_base_fixed_len(CASE_INSENSITIVE));
debug!("generate_session_dir_path: directory_name = {}", directory_name);
let directory_path = crate_dir.join(directory_name);
debug!("generate_session_dir_path: directory_path = {}", directory_path.display());
@@ -588,10 +585,10 @@ fn extract_timestamp_from_session_dir(directory_name: &str) -> Result String {
+fn timestamp_to_string(timestamp: SystemTime) -> BaseNString {
let duration = timestamp.duration_since(UNIX_EPOCH).unwrap();
let micros = duration.as_secs() * 1_000_000 + (duration.subsec_nanos() as u64) / 1000;
- base_n::encode(micros as u128, INT_ENCODE_BASE)
+ micros.to_base_fixed_len(CASE_INSENSITIVE)
}
fn string_to_timestamp(s: &str) -> Result {
@@ -622,9 +619,8 @@ fn crate_path(sess: &Session) -> PathBuf {
sess.cfg_version,
);
- let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
-
- let crate_name = format!("{crate_name}-{stable_crate_id}");
+ let crate_name =
+ format!("{crate_name}-{}", stable_crate_id.as_u64().to_base_fixed_len(CASE_INSENSITIVE));
incr_dir.join(crate_name)
}
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index b593c41a8eaf..76d5d7a3ac2f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -4,7 +4,6 @@ use crate::proc_macro_decls;
use crate::util;
use rustc_ast::{self as ast, visit};
-use rustc_borrowck as mir_borrowck;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::parallel;
use rustc_data_structures::steal::Steal;
@@ -20,7 +19,6 @@ use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_middle::util::Providers;
-use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{abi_test, hir_stats, layout_test};
use rustc_resolve::Resolver;
@@ -616,8 +614,8 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| {
proc_macro_decls::provide(providers);
rustc_const_eval::provide(providers);
rustc_middle::hir::provide(providers);
- mir_borrowck::provide(providers);
- mir_build::provide(providers);
+ rustc_borrowck::provide(providers);
+ rustc_mir_build::provide(providers);
rustc_mir_transform::provide(providers);
rustc_monomorphize::provide(providers);
rustc_privacy::provide(providers);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index db150cc1f875..36f9dda7250c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -20,7 +20,7 @@ use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
use rustc_span::symbol::sym;
use rustc_span::{FileName, SourceFileHashAlgorithm};
use rustc_target::spec::{
- CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi,
+ CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
@@ -809,6 +809,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(no_profiler_runtime, true);
tracked!(no_trait_vptr, true);
tracked!(no_unique_section_names, true);
+ tracked!(on_broken_pipe, OnBrokenPipe::Kill);
tracked!(oom, OomStrategy::Panic);
tracked!(osx_rpath_install_name, true);
tracked!(packed_bundled_libs, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 02dcfe9c8dff..ce4d38250152 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -7,18 +7,16 @@ use rustc_data_structures::sync;
use rustc_metadata::{load_symbol_from_dylib, DylibError};
use rustc_middle::ty::CurrentGcx;
use rustc_parse::validate_attr;
-use rustc_session as session;
-use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes};
+use rustc_session::config::{host_triple, Cfg, OutFileName, OutputFilenames, OutputTypes};
use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
-use rustc_session::{filesearch, Session};
+use rustc_session::output::{categorize_crate_type, CRATE_TYPES};
+use rustc_session::{filesearch, EarlyDiagCtxt, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::source_map::SourceMapInputs;
use rustc_span::symbol::sym;
use rustc_target::spec::Target;
-use session::output::{categorize_crate_type, CRATE_TYPES};
-use session::EarlyDiagCtxt;
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
@@ -286,7 +284,7 @@ fn get_codegen_sysroot(
"cannot load the default codegen backend twice"
);
- let target = session::config::host_triple();
+ let target = host_triple();
let sysroot_candidates = sysroot_candidates();
let sysroot = iter::once(sysroot)
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 1f0a8a0b5678..c1f5cd45dc82 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -74,9 +74,12 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
GenericArg::Type(ty) => {
cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
}
- GenericArg::Const(c) => {
- cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into())
- }
+ GenericArg::Const(c) => cx
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(c.value.span)
+ .unwrap_or_else(|_| "_".into()),
GenericArg::Infer(_) => String::from("_"),
})
.collect::>();
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c0c773c6285c..c7aea137b684 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -885,7 +885,7 @@ impl<'hir> Map<'hir> {
Node::ImplItem(impl_item) => impl_item.span,
Node::Variant(variant) => variant.span,
Node::Field(field) => field.span,
- Node::AnonConst(constant) => self.body(constant.body).value.span,
+ Node::AnonConst(constant) => constant.span,
Node::ConstBlock(constant) => self.body(constant.body).value.span,
Node::Expr(expr) => expr.span,
Node::ExprField(field) => field.span,
@@ -912,7 +912,7 @@ impl<'hir> Map<'hir> {
Node::ArrayLenInfer(inf) => inf.span,
Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span,
Node::Synthetic => unreachable!(),
- Node::Err(span) => *span,
+ Node::Err(span) => span,
}
}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 9d9ca22247ad..477303e2434f 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -277,7 +277,7 @@ pub struct FunctionCoverageInfo {
pub mappings: Vec,
/// The depth of the deepest decision is used to know how many
/// temp condbitmaps should be allocated for the function.
- pub mcdc_max_decision_depth: u16,
+ pub mcdc_num_condition_bitmaps: usize,
}
/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR.
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 6d4585cfbc66..daab6c855819 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,7 +1,9 @@
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
use crate::ty::{GenericArgs, Instance, InstanceDef, SymbolName, TyCtxt};
use rustc_attr::InlineAttr;
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::BaseNString;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::CASE_INSENSITIVE;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxIndexMap;
@@ -337,14 +339,11 @@ impl<'tcx> CodegenUnit<'tcx> {
self.is_code_coverage_dead_code_cgu = true;
}
- pub fn mangle_name(human_readable_name: &str) -> String {
- // We generate a 80 bit hash from the name. This should be enough to
- // avoid collisions and is still reasonably short for filenames.
+ pub fn mangle_name(human_readable_name: &str) -> BaseNString {
let mut hasher = StableHasher::new();
human_readable_name.hash(&mut hasher);
let hash: Hash128 = hasher.finish();
- let hash = hash.as_u128() & ((1u128 << 80) - 1);
- base_n::encode(hash, base_n::CASE_INSENSITIVE)
+ hash.as_u128().to_base_fixed_len(CASE_INSENSITIVE)
}
pub fn compute_size_estimate(&mut self) {
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 4c34bf88c7f9..3ad6b68d1299 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -273,6 +273,8 @@ pub enum GoalSource {
/// they are from an impl where-clause. This is necessary due to
/// backwards compatability, cc trait-system-refactor-initiatitive#70.
ImplWhereBound,
+ /// Instantiating a higher-ranked goal and re-proving it.
+ InstantiateHigherRanked,
}
/// Possible ways the given goal can be proven.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
index 2d73be387fdc..11aa0e10931c 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs
@@ -127,6 +127,7 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
let source = match source {
GoalSource::Misc => "misc",
GoalSource::ImplWhereBound => "impl where-bound",
+ GoalSource::InstantiateHigherRanked => "higher-ranked goal",
};
writeln!(this.f, "ADDED GOAL ({source}): {goal:?}")?
}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index d6e6cc957b4b..794e7ebb7b43 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -566,7 +566,8 @@ fn construct_const<'a, 'tcx>(
span,
..
}) => (*span, ty.span),
- Node::AnonConst(_) | Node::ConstBlock(_) => {
+ Node::AnonConst(ct) => (ct.span, ct.span),
+ Node::ConstBlock(_) => {
let span = tcx.def_span(def);
(span, span)
}
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 0119b95cced9..c1f9313a377d 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -3,7 +3,6 @@ use rustc_index::IndexSlice;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::impls::borrowed_locals;
use crate::ssa::SsaLocals;
@@ -32,8 +31,8 @@ impl<'tcx> MirPass<'tcx> for CopyProp {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let borrowed_locals = borrowed_locals(body);
- let ssa = SsaLocals::new(body);
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let ssa = SsaLocals::new(tcx, body, param_env);
let fully_moved = fully_moved_locals(&ssa, body);
debug!(?fully_moved);
@@ -51,7 +50,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
tcx,
copy_classes: ssa.copy_classes(),
fully_moved,
- borrowed_locals,
+ borrowed_locals: ssa.borrowed_locals(),
storage_to_remove,
}
.visit_body_preserves_cfg(body);
@@ -101,7 +100,7 @@ struct Replacer<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
fully_moved: BitSet,
storage_to_remove: BitSet,
- borrowed_locals: BitSet,
+ borrowed_locals: &'a BitSet,
copy_classes: &'a IndexSlice,
}
@@ -112,6 +111,12 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
let new_local = self.copy_classes[*local];
+ // We must not unify two locals that are borrowed. But this is fine if one is borrowed and
+ // the other is not. We chose to check the original local, and not the target. That way, if
+ // the original local is borrowed and the target is not, we do not pessimize the whole class.
+ if self.borrowed_locals.contains(*local) {
+ return;
+ }
match ctxt {
// Do not modify the local in storage statements.
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
@@ -122,32 +127,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
}
}
- fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+ fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
if let Some(new_projection) = self.process_projection(place.projection, loc) {
place.projection = self.tcx().mk_place_elems(&new_projection);
}
- let observes_address = match ctxt {
- PlaceContext::NonMutatingUse(
- NonMutatingUseContext::SharedBorrow
- | NonMutatingUseContext::FakeBorrow
- | NonMutatingUseContext::AddressOf,
- ) => true,
- // For debuginfo, merging locals is ok.
- PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
- self.borrowed_locals.contains(place.local)
- }
- _ => false,
- };
- if observes_address && !place.is_indirect() {
- // We observe the address of `place.local`. Do not replace it.
- } else {
- self.visit_local(
- &mut place.local,
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
- loc,
- )
- }
+ // Any non-mutating use context is ok.
+ let ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
+ self.visit_local(&mut place.local, ctxt, loc)
}
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 9edde6662469..ffe61e761c53 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -102,7 +102,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
- let mcdc_max_decision_depth = coverage_spans
+ let mcdc_num_condition_bitmaps = coverage_spans
.mappings
.iter()
.filter_map(|bcb_mapping| match bcb_mapping.kind {
@@ -110,7 +110,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
_ => None,
})
.max()
- .unwrap_or(0);
+ .map_or(0, |max| usize::from(max) + 1);
mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
function_source_hash: hir_info.function_source_hash,
@@ -118,7 +118,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(),
expressions: coverage_counters.into_expressions(),
mappings,
- mcdc_max_decision_depth,
+ mcdc_num_condition_bitmaps,
}));
}
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 24832086b167..4dd595ce1e1c 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -121,7 +121,7 @@ impl<'tcx> MirPass<'tcx> for GVN {
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
- let ssa = SsaLocals::new(body);
+ let ssa = SsaLocals::new(tcx, body, param_env);
// Clone dominators as we need them while mutating the body.
let dominators = body.basic_blocks.dominators().clone();
@@ -724,6 +724,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
// Invariant: `value` holds the value up-to the `index`th projection excluded.
let mut value = self.locals[place.local]?;
for (index, proj) in place.projection.iter().enumerate() {
+ if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
+ && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
+ && let AddressKind::Ref(BorrowKind::Shared) = kind
+ && let Some(v) = self.simplify_place_value(&mut pointee, location)
+ {
+ value = v;
+ place_ref = pointee.project_deeper(&place.projection[index..], self.tcx).as_ref();
+ }
if let Some(local) = self.try_as_local(value, location) {
// Both `local` and `Place { local: place.local, projection: projection[..index] }`
// hold the same value. Therefore, following place holds the value in the original
@@ -735,6 +743,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
value = self.project(base, value, proj)?;
}
+ if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
+ && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
+ && let AddressKind::Ref(BorrowKind::Shared) = kind
+ && let Some(v) = self.simplify_place_value(&mut pointee, location)
+ {
+ value = v;
+ place_ref = pointee.project_deeper(&[], self.tcx).as_ref();
+ }
if let Some(new_local) = self.try_as_local(value, location) {
place_ref = PlaceRef { local: new_local, projection: &[] };
}
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 128634bd7f25..c26a54616331 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -22,7 +22,8 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
}
fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let ssa = SsaLocals::new(body);
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let ssa = SsaLocals::new(tcx, body, param_env);
let slice_lengths = compute_slice_length(tcx, &ssa, body);
debug!(?slice_lengths);
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index d5642be55137..044ae32c1d40 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -82,7 +82,8 @@ impl<'tcx> MirPass<'tcx> for ReferencePropagation {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
- let ssa = SsaLocals::new(body);
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ let ssa = SsaLocals::new(tcx, body, param_env);
let mut replacer = compute_replacement(tcx, body, &ssa);
debug!(?replacer.targets);
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index fddc62e6652f..55fed7d9da28 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -2,8 +2,9 @@
//! 1/ They are only assigned-to once, either as a function parameter, or in an assign statement;
//! 2/ This single assignment dominates all uses;
//!
-//! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
-//! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
+//! As we do not track indirect assignments, a local that has its address taken (either by
+//! AddressOf or by borrowing) is considered non-SSA. However, it is UB to modify through an
+//! immutable borrow of a `Freeze` local. Those can still be considered to be SSA.
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
@@ -11,6 +12,7 @@ use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
pub struct SsaLocals {
/// Assignments to each local. This defines whether the local is SSA.
@@ -24,6 +26,8 @@ pub struct SsaLocals {
/// Number of "direct" uses of each local, ie. uses that are not dereferences.
/// We ignore non-uses (Storage statements, debuginfo).
direct_uses: IndexVec,
+ /// Set of SSA locals that are immutably borrowed.
+ borrowed_locals: BitSet,
}
pub enum AssignedValue<'a, 'tcx> {
@@ -33,15 +37,22 @@ pub enum AssignedValue<'a, 'tcx> {
}
impl SsaLocals {
- pub fn new<'tcx>(body: &Body<'tcx>) -> SsaLocals {
+ pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ParamEnv<'tcx>) -> SsaLocals {
let assignment_order = Vec::with_capacity(body.local_decls.len());
let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
let dominators = body.basic_blocks.dominators();
let direct_uses = IndexVec::from_elem(0, &body.local_decls);
- let mut visitor =
- SsaVisitor { body, assignments, assignment_order, dominators, direct_uses };
+ let borrowed_locals = BitSet::new_empty(body.local_decls.len());
+ let mut visitor = SsaVisitor {
+ body,
+ assignments,
+ assignment_order,
+ dominators,
+ direct_uses,
+ borrowed_locals,
+ };
for local in body.args_iter() {
visitor.assignments[local] = Set1::One(DefLocation::Argument);
@@ -58,6 +69,16 @@ impl SsaLocals {
visitor.visit_var_debug_info(var_debug_info);
}
+ // The immutability of shared borrows only works on `Freeze` locals. If the visitor found
+ // borrows, we need to check the types. For raw pointers and mutable borrows, the locals
+ // have already been marked as non-SSA.
+ debug!(?visitor.borrowed_locals);
+ for local in visitor.borrowed_locals.iter() {
+ if !body.local_decls[local].ty.is_freeze(tcx, param_env) {
+ visitor.assignments[local] = Set1::Many;
+ }
+ }
+
debug!(?visitor.assignments);
debug!(?visitor.direct_uses);
@@ -70,6 +91,7 @@ impl SsaLocals {
assignments: visitor.assignments,
assignment_order: visitor.assignment_order,
direct_uses: visitor.direct_uses,
+ borrowed_locals: visitor.borrowed_locals,
// This is filled by `compute_copy_classes`.
copy_classes: IndexVec::default(),
};
@@ -174,6 +196,11 @@ impl SsaLocals {
&self.copy_classes
}
+ /// Set of SSA locals that are immutably borrowed.
+ pub fn borrowed_locals(&self) -> &BitSet {
+ &self.borrowed_locals
+ }
+
/// Make a property uniform on a copy equivalence class by removing elements.
pub fn meet_copy_equivalence(&self, property: &mut BitSet) {
// Consolidate to have a local iff all its copies are.
@@ -208,6 +235,8 @@ struct SsaVisitor<'tcx, 'a> {
assignments: IndexVec>,
assignment_order: Vec,
direct_uses: IndexVec,
+ // Track locals that are immutably borrowed, so we can check their type is `Freeze` later.
+ borrowed_locals: BitSet,
}
impl SsaVisitor<'_, '_> {
@@ -232,16 +261,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
| PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(),
// Anything can happen with raw pointers, so remove them.
- // We do not verify that all uses of the borrow dominate the assignment to `local`,
- // so we have to remove them too.
- PlaceContext::NonMutatingUse(
- NonMutatingUseContext::SharedBorrow
- | NonMutatingUseContext::FakeBorrow
- | NonMutatingUseContext::AddressOf,
- )
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
| PlaceContext::MutatingUse(_) => {
self.assignments[local] = Set1::Many;
}
+ // Immutable borrows are ok, but we need to delay a check that the type is `Freeze`.
+ PlaceContext::NonMutatingUse(
+ NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow,
+ ) => {
+ self.borrowed_locals.insert(local);
+ self.check_dominates(local, loc);
+ self.direct_uses[local] += 1;
+ }
PlaceContext::NonMutatingUse(_) => {
self.check_dominates(local, loc);
self.direct_uses[local] += 1;
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index a545c170297d..8878310d6e93 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -695,9 +695,6 @@ passes_transparent_incompatible =
passes_undefined_naked_function_abi =
Rust ABI is unsupported in naked functions
-passes_unix_sigpipe_values =
- valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
-
passes_unknown_external_lang_item =
unknown external lang item: `{$lang_item}`
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c403e9196fab..e60aa27dba2b 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2523,7 +2523,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
sym::automatically_derived,
sym::start,
sym::rustc_main,
- sym::unix_sigpipe,
sym::derive,
sym::test,
sym::test_case,
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 438c583db49e..d52092f2aa92 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -12,8 +12,7 @@ use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
use crate::errors::{
- AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
- MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
+ AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr,
};
struct EntryContext<'tcx> {
@@ -67,11 +66,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
);
match entry_point_type {
- EntryPointType::None => {
- if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
- ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
- }
- }
+ EntryPointType::None => (),
_ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
for attr in [sym::start, sym::rustc_main] {
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
@@ -81,9 +76,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
}
EntryPointType::MainNamed => (),
EntryPointType::OtherMain => {
- if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
- ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
- }
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
}
EntryPointType::RustcMainAttr => {
@@ -98,9 +90,6 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
}
}
EntryPointType::Start => {
- if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
- ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
- }
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
@@ -120,7 +109,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
Some((def_id.to_def_id(), EntryFnType::Start))
} else if let Some((local_def_id, _)) = visitor.attr_main_fn {
let def_id = local_def_id.to_def_id();
- Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
+ Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
} else {
if let Some(main_def) = tcx.resolutions(()).main_def
&& let Some(def_id) = main_def.opt_fn_def_id()
@@ -133,31 +122,19 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
return None;
}
- return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }));
+ return Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }));
}
no_main_err(tcx, visitor);
None
}
}
-fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
- if let Some(attr) = tcx.get_attr(def_id, sym::unix_sigpipe) {
- match (attr.value_str(), attr.meta_item_list()) {
- (Some(sym::inherit), None) => sigpipe::INHERIT,
- (Some(sym::sig_ign), None) => sigpipe::SIG_IGN,
- (Some(sym::sig_dfl), None) => sigpipe::SIG_DFL,
- (Some(_), None) => {
- tcx.dcx().emit_err(UnixSigpipeValues { span: attr.span });
- sigpipe::DEFAULT
- }
- _ => {
- // Keep going so that `fn emit_malformed_attribute()` can print
- // an excellent error message
- sigpipe::DEFAULT
- }
- }
- } else {
- sigpipe::DEFAULT
+fn sigpipe(tcx: TyCtxt<'_>) -> u8 {
+ match tcx.sess.opts.unstable_opts.on_broken_pipe {
+ rustc_target::spec::OnBrokenPipe::Default => sigpipe::DEFAULT,
+ rustc_target::spec::OnBrokenPipe::Kill => sigpipe::SIG_DFL,
+ rustc_target::spec::OnBrokenPipe::Error => sigpipe::SIG_IGN,
+ rustc_target::spec::OnBrokenPipe::Inherit => sigpipe::INHERIT,
}
}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 03a607348e88..743faf545607 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1259,13 +1259,6 @@ pub struct ExternMain {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(passes_unix_sigpipe_values)]
-pub struct UnixSigpipeValues {
- #[primary_span]
- pub span: Span,
-}
-
pub struct NoMainErr {
pub sp: Span,
pub crate_name: Symbol,
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index e7a32771f350..f998e0ff1547 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -11,7 +11,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
-rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 6ea87a4a633e..4d845ab0d07b 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -19,7 +19,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
-rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 12484462f82f..01e279b6d04f 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1617,7 +1617,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let post = format!(", consider renaming `{}` into `{snippet}`", suggestion.candidate);
(span, snippet, post)
} else {
- (span, suggestion.candidate.to_string(), String::new())
+ (span, suggestion.candidate.to_ident_string(), String::new())
};
let msg = match suggestion.target {
SuggestionTarget::SimilarlyNamed => format!(
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 82e41b6c3143..35bf3f761df3 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -141,7 +141,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
}
// We implicitly add `rustfmt`, `clippy`, `diagnostic` to known tools,
// but it's not an error to register them explicitly.
- let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic];
+ let predefined_tools = [sym::clippy, sym::rustfmt, sym::diagnostic, sym::miri];
registered_tools.extend(predefined_tools.iter().cloned().map(Ident::with_dummy_span));
registered_tools
}
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 40cd0c14b05f..d67132d2dd4f 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -4,7 +4,9 @@
//!
//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
//! see design document in the tracking issue #89653.
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
+use rustc_data_structures::base_n::ALPHANUMERIC_ONLY;
+use rustc_data_structures::base_n::CASE_INSENSITIVE;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::bug;
@@ -736,7 +738,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
/// ).
fn to_disambiguator(num: u64) -> String {
if let Some(num) = num.checked_sub(1) {
- format!("s{}_", base_n::encode(num as u128, base_n::ALPHANUMERIC_ONLY))
+ format!("s{}_", num.to_base(ALPHANUMERIC_ONLY))
} else {
"s_".to_string()
}
@@ -746,7 +748,7 @@ fn to_disambiguator(num: u64) -> String {
/// ).
fn to_seq_id(num: usize) -> String {
if let Some(num) = num.checked_sub(1) {
- base_n::encode(num as u128, base_n::CASE_INSENSITIVE).to_uppercase()
+ (num as u64).to_base(CASE_INSENSITIVE).to_uppercase()
} else {
"".to_string()
}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index ad66e5e1c2b4..f2bdabbf3942 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2909,7 +2909,9 @@ pub(crate) mod dep_tracking {
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
- use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel, WasmCAbi};
+ use rustc_target::spec::{
+ CodeModel, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, WasmCAbi,
+ };
use rustc_target::spec::{
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
};
@@ -2973,6 +2975,7 @@ pub(crate) mod dep_tracking {
InstrumentXRay,
CrateType,
MergeFunctions,
+ OnBrokenPipe,
PanicStrategy,
RelroLevel,
OptLevel,
diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs
index 1fadc75cfd0d..1830ee034855 100644
--- a/compiler/rustc_session/src/config/sigpipe.rs
+++ b/compiler/rustc_session/src/config/sigpipe.rs
@@ -1,6 +1,6 @@
//! NOTE: Keep these constants in sync with `library/std/src/sys/pal/unix/mod.rs`!
-/// The default value if `#[unix_sigpipe]` is not specified. This resolves
+/// The default value if `-Zon-broken-pipe=...` is not specified. This resolves
/// to `SIG_IGN` in `library/std/src/sys/pal/unix/mod.rs`.
///
/// Note that `SIG_IGN` has been the Rust default since 2014. See
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7355e5b69534..65660286dd73 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -12,7 +12,7 @@ use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{
- CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet, WasmCAbi,
+ CodeModel, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, SanitizerSet, WasmCAbi,
};
use rustc_target::spec::{
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@@ -378,6 +378,7 @@ mod desc {
pub const parse_time_passes_format: &str = "`text` (default) or `json`";
pub const parse_passes: &str = "a space-separated list of passes, or `all`";
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
+ pub const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
@@ -708,6 +709,17 @@ mod parse {
true
}
+ pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
+ match v {
+ // OnBrokenPipe::Default can't be explicitly specified
+ Some("kill") => *slot = OnBrokenPipe::Kill,
+ Some("error") => *slot = OnBrokenPipe::Error,
+ Some("inherit") => *slot = OnBrokenPipe::Inherit,
+ _ => return false,
+ }
+ true
+ }
+
pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
match v {
Some("panic") => *slot = OomStrategy::Panic,
@@ -1833,6 +1845,8 @@ options! {
"do not use unique names for text and data sections when -Z function-sections is used"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
"normalize associated items in rustdoc when generating documentation"),
+ on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
+ "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
"panic strategy for out-of-memory handling"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7fe94c2e82ba..9c556f1152a5 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1936,7 +1936,6 @@ symbols! {
unit,
universal_impl_trait,
unix,
- unix_sigpipe,
unlikely,
unmarked_api,
unnamed_fields,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index fc2c3dcb2d95..5cdfb773b5cb 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::base_n;
+use rustc_data_structures::base_n::ToBaseN;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::intern::Interned;
use rustc_hir as hir;
@@ -832,7 +832,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
/// e.g. `1` becomes `"0_"`, `62` becomes `"Z_"`, etc.
pub(crate) fn push_integer_62(x: u64, output: &mut String) {
if let Some(x) = x.checked_sub(1) {
- base_n::push_str(x as u128, base_n::ALPHANUMERIC_ONLY, output);
+ output.push_str(&x.to_base(62));
}
output.push('_');
}
diff --git a/compiler/rustc_target/src/spec/base/fuchsia.rs b/compiler/rustc_target/src/spec/base/fuchsia.rs
index 4c2775850d13..d1ac22f3a098 100644
--- a/compiler/rustc_target/src/spec/base/fuchsia.rs
+++ b/compiler/rustc_target/src/spec/base/fuchsia.rs
@@ -1,4 +1,6 @@
-use crate::spec::{crt_objects, cvs, Cc, LinkOutputKind, LinkerFlavor, Lld, TargetOptions};
+use crate::spec::{
+ crt_objects, cvs, Cc, FramePointer, LinkOutputKind, LinkerFlavor, Lld, TargetOptions,
+};
pub fn opts() -> TargetOptions {
// This mirrors the linker options provided by clang. We presume lld for
@@ -38,6 +40,7 @@ pub fn opts() -> TargetOptions {
]),
position_independent_executables: true,
has_thread_local: true,
+ frame_pointer: FramePointer::NonLeaf,
..Default::default()
}
}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index bd347c1b4b3f..cbb248a0fc21 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -778,6 +778,14 @@ pub enum PanicStrategy {
Abort,
}
+#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
+pub enum OnBrokenPipe {
+ Default,
+ Kill,
+ Error,
+ Inherit,
+}
+
impl PanicStrategy {
pub fn desc(&self) -> &str {
match *self {
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 280975f63bd3..f2ca42a0be91 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -58,15 +58,15 @@ pub(super) trait GoalKind<'tcx>:
/// goal by equating it with the assumption.
fn probe_and_consider_implied_clause(
ecx: &mut EvalCtxt<'_, 'tcx>,
- source: CandidateSource,
+ parent_source: CandidateSource,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
- requirements: impl IntoIterator- >>,
+ requirements: impl IntoIterator
- >)>,
) -> Result, NoSolution> {
- Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
- // FIXME(-Znext-solver=coinductive): check whether this should be
- // `GoalSource::ImplWhereBound` for any caller.
- ecx.add_goals(GoalSource::Misc, requirements);
+ Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
+ for (nested_source, goal) in requirements {
+ ecx.add_goal(nested_source, goal);
+ }
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -85,9 +85,8 @@ pub(super) trait GoalKind<'tcx>:
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
};
- // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
ecx.add_goals(
- GoalSource::Misc,
+ GoalSource::ImplWhereBound,
structural_traits::predicates_for_object_candidate(
ecx,
goal.param_env,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 6722abd709c3..d6bf2b596ef1 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -90,6 +90,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self,
certainty: Certainty,
) -> QueryResult<'tcx> {
+ self.inspect.make_canonical_response(certainty);
+
let goals_certainty = self.try_evaluate_added_goals()?;
assert_eq!(
self.tainted,
@@ -98,8 +100,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
previous call to `try_evaluate_added_goals!`"
);
- self.inspect.make_canonical_response(certainty);
-
// When normalizing, we've replaced the expected term with an unconstrained
// inference variable. This means that we dropped information which could
// have been important. We handle this by instead returning the nested goals
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 1710746ae504..bae1c6b60115 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -454,7 +454,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
} else {
self.infcx.enter_forall(kind, |kind| {
let goal = goal.with(self.tcx(), ty::Binder::dummy(kind));
- self.add_goal(GoalSource::Misc, goal);
+ self.add_goal(GoalSource::InstantiateHigherRanked, goal);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 3fa409eefffc..796222129f18 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -1,15 +1,19 @@
use std::mem;
+use std::ops::ControlFlow;
use rustc_infer::infer::InferCtxt;
-use rustc_infer::traits::solve::MaybeCause;
+use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::solve::inspect::ProbeKind;
+use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
use rustc_infer::traits::{
- query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
- PredicateObligation, SelectionError, TraitEngine,
+ self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
+ ObligationCause, PredicateObligation, SelectionError, TraitEngine,
};
-use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::{self, TyCtxt};
use super::eval_ctxt::GenerateProofTree;
+use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor};
use super::{Certainty, InferCtxtEvalExt};
/// A trait engine using the new trait solver.
@@ -133,9 +137,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
.collect();
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
- root_obligation: obligation.clone(),
+ obligation: find_best_leaf_obligation(infcx, &obligation),
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
- obligation,
+ root_obligation: obligation,
}));
errors
@@ -192,8 +196,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
fn fulfillment_error_for_no_solution<'tcx>(
infcx: &InferCtxt<'tcx>,
- obligation: PredicateObligation<'tcx>,
+ root_obligation: PredicateObligation<'tcx>,
) -> FulfillmentError<'tcx> {
+ let obligation = find_best_leaf_obligation(infcx, &root_obligation);
+
let code = match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
FulfillmentErrorCode::ProjectionError(
@@ -234,7 +240,8 @@ fn fulfillment_error_for_no_solution<'tcx>(
bug!("unexpected goal: {obligation:?}")
}
};
- FulfillmentError { root_obligation: obligation.clone(), code, obligation }
+
+ FulfillmentError { obligation, code, root_obligation }
}
fn fulfillment_error_for_stalled<'tcx>(
@@ -258,5 +265,136 @@ fn fulfillment_error_for_stalled<'tcx>(
}
});
- FulfillmentError { obligation: obligation.clone(), code, root_obligation: obligation }
+ FulfillmentError {
+ obligation: find_best_leaf_obligation(infcx, &obligation),
+ code,
+ root_obligation: obligation,
+ }
+}
+
+fn find_best_leaf_obligation<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+) -> PredicateObligation<'tcx> {
+ let obligation = infcx.resolve_vars_if_possible(obligation.clone());
+ infcx
+ .visit_proof_tree(
+ obligation.clone().into(),
+ &mut BestObligation { obligation: obligation.clone() },
+ )
+ .break_value()
+ .unwrap_or(obligation)
+}
+
+struct BestObligation<'tcx> {
+ obligation: PredicateObligation<'tcx>,
+}
+
+impl<'tcx> BestObligation<'tcx> {
+ fn with_derived_obligation(
+ &mut self,
+ derived_obligation: PredicateObligation<'tcx>,
+ and_then: impl FnOnce(&mut Self) -> >::Result,
+ ) -> >::Result {
+ let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
+ let res = and_then(self);
+ self.obligation = old_obligation;
+ res
+ }
+}
+
+impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
+ type Result = ControlFlow>;
+
+ fn span(&self) -> rustc_span::Span {
+ self.obligation.cause.span
+ }
+
+ fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+ // FIXME: Throw out candidates that have no failing WC and >0 failing misc goal.
+ // This most likely means that the goal just didn't unify at all, e.g. a param
+ // candidate with an alias in it.
+ let candidates = goal.candidates();
+
+ let [candidate] = candidates.as_slice() else {
+ return ControlFlow::Break(self.obligation.clone());
+ };
+
+ // FIXME: Could we extract a trait ref from a projection here too?
+ // FIXME: Also, what about considering >1 layer up the stack? May be necessary
+ // for normalizes-to.
+ let Some(parent_trait_pred) = goal.goal().predicate.to_opt_poly_trait_pred() else {
+ return ControlFlow::Break(self.obligation.clone());
+ };
+
+ let tcx = goal.infcx().tcx;
+ let mut impl_where_bound_count = 0;
+ for nested_goal in candidate.instantiate_nested_goals(self.span()) {
+ let obligation;
+ match nested_goal.source() {
+ GoalSource::Misc => {
+ continue;
+ }
+ GoalSource::ImplWhereBound => {
+ obligation = Obligation {
+ cause: derive_cause(
+ tcx,
+ candidate.kind(),
+ self.obligation.cause.clone(),
+ impl_where_bound_count,
+ parent_trait_pred,
+ ),
+ param_env: nested_goal.goal().param_env,
+ predicate: nested_goal.goal().predicate,
+ recursion_depth: self.obligation.recursion_depth + 1,
+ };
+ impl_where_bound_count += 1;
+ }
+ GoalSource::InstantiateHigherRanked => {
+ obligation = self.obligation.clone();
+ }
+ }
+
+ // Skip nested goals that hold.
+ //FIXME: We should change the max allowed certainty based on if we're
+ // visiting an ambiguity or error obligation.
+ if matches!(nested_goal.result(), Ok(Certainty::Yes)) {
+ continue;
+ }
+
+ self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
+ }
+
+ ControlFlow::Break(self.obligation.clone())
+ }
+}
+
+fn derive_cause<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ candidate_kind: ProbeKind<'tcx>,
+ mut cause: ObligationCause<'tcx>,
+ idx: usize,
+ parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
+) -> ObligationCause<'tcx> {
+ match candidate_kind {
+ ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => {
+ if let Some((_, span)) =
+ tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
+ {
+ cause = cause.derived_cause(parent_trait_pred, |derived| {
+ traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: impl_def_id,
+ impl_def_predicate_index: Some(idx),
+ span,
+ }))
+ })
+ }
+ }
+ ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => {
+ cause = cause.derived_cause(parent_trait_pred, traits::BuiltinDerivedObligation);
+ }
+ _ => {}
+ };
+ cause
}
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 97de25295b81..4f79f1b2aafe 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -41,6 +41,7 @@ pub struct InspectGoal<'a, 'tcx> {
result: Result,
evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>,
normalizes_to_term_hack: Option>,
+ source: GoalSource,
}
/// The expected term of a `NormalizesTo` goal gets replaced
@@ -90,7 +91,7 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
pub struct InspectCandidate<'a, 'tcx> {
goal: &'a InspectGoal<'a, 'tcx>,
kind: inspect::ProbeKind<'tcx>,
- nested_goals: Vec>>>,
+ nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>,
final_state: inspect::CanonicalState<'tcx, ()>,
result: QueryResult<'tcx>,
shallow_certainty: Certainty,
@@ -125,10 +126,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
/// back their inference constraints. This function modifies
/// the state of the `infcx`.
pub fn visit_nested_no_probe>(&self, visitor: &mut V) -> V::Result {
- if self.goal.depth < visitor.config().max_depth {
- for goal in self.instantiate_nested_goals(visitor.span()) {
- try_visit!(visitor.visit_goal(&goal));
- }
+ for goal in self.instantiate_nested_goals(visitor.span()) {
+ try_visit!(goal.visit_with(visitor));
}
V::Result::output()
@@ -143,13 +142,16 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
let instantiated_goals: Vec<_> = self
.nested_goals
.iter()
- .map(|goal| {
- canonical::instantiate_canonical_state(
- infcx,
- span,
- param_env,
- &mut orig_values,
- *goal,
+ .map(|(source, goal)| {
+ (
+ *source,
+ canonical::instantiate_canonical_state(
+ infcx,
+ span,
+ param_env,
+ &mut orig_values,
+ *goal,
+ ),
)
})
.collect();
@@ -171,7 +173,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
instantiated_goals
.into_iter()
- .map(|goal| match goal.predicate.kind().no_bound_vars() {
+ .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
let unconstrained_term = match term.unpack() {
ty::TermKind::Ty(_) => infcx
@@ -195,6 +197,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
self.goal.depth + 1,
proof_tree.unwrap(),
Some(NormalizesToTermHack { term, unconstrained_term }),
+ source,
)
}
_ => InspectGoal::new(
@@ -202,6 +205,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
self.goal.depth + 1,
infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(),
None,
+ source,
),
})
.collect()
@@ -227,16 +231,23 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
self.result
}
+ pub fn source(&self) -> GoalSource {
+ self.source
+ }
+
fn candidates_recur(
&'a self,
candidates: &mut Vec>,
- nested_goals: &mut Vec>>>,
+ nested_goals: &mut Vec<(
+ GoalSource,
+ inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>,
+ )>,
probe: &inspect::Probe<'tcx>,
) {
let mut shallow_certainty = None;
for step in &probe.steps {
match step {
- &inspect::ProbeStep::AddGoal(_source, goal) => nested_goals.push(goal),
+ &inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
inspect::ProbeStep::NestedProbe(ref probe) => {
// Nested probes have to prove goals added in their parent
// but do not leak them, so we truncate the added goals
@@ -319,6 +330,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
depth: usize,
root: inspect::GoalEvaluation<'tcx>,
normalizes_to_term_hack: Option>,
+ source: GoalSource,
) -> Self {
let inspect::GoalEvaluation { uncanonicalized_goal, kind, evaluation } = root;
let inspect::GoalEvaluationKind::Root { orig_values } = kind else { unreachable!() };
@@ -341,8 +353,17 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
result,
evaluation_kind: evaluation.kind,
normalizes_to_term_hack,
+ source,
}
}
+
+ pub(crate) fn visit_with>(&self, visitor: &mut V) -> V::Result {
+ if self.depth < visitor.config().max_depth {
+ try_visit!(visitor.visit_goal(self));
+ }
+
+ V::Result::output()
+ }
}
/// The public API to interact with proof trees.
@@ -367,6 +388,6 @@ impl<'tcx> InferCtxt<'tcx> {
) -> V::Result {
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
let proof_tree = proof_tree.unwrap();
- visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree, None))
+ visitor.visit_goal(&InspectGoal::new(self, 0, proof_tree, None, GoalSource::Misc))
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index dab87fffe461..f886c5886504 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -389,7 +389,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
pred,
- [goal.with(tcx, output_is_sized_pred)],
+ [(GoalSource::ImplWhereBound, goal.with(tcx, output_is_sized_pred))],
)
}
@@ -473,7 +473,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
pred,
[goal.with(tcx, output_is_sized_pred)]
.into_iter()
- .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))),
+ .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred)))
+ .map(|goal| (GoalSource::ImplWhereBound, goal)),
)
}
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index c8cb14abb554..d2b893d6383b 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -321,7 +321,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
pred,
- [goal.with(tcx, output_is_sized_pred)],
+ [(GoalSource::ImplWhereBound, goal.with(tcx, output_is_sized_pred))],
)
}
@@ -367,7 +367,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
pred,
[goal.with(tcx, output_is_sized_pred)]
.into_iter()
- .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))),
+ .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred)))
+ .map(|goal| (GoalSource::ImplWhereBound, goal)),
)
}
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 6a64eaf576bb..f143e5578717 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -41,6 +41,7 @@ use crate::sync::Arc;
/// or anything that implements
[Into]<[Vec]<[u8]>> (for
/// example, you can build a `CString` straight out of a [`String`] or
/// a &[str], since both implement that trait).
+/// You can create a `CString` from a literal with `CString::from(c"Text")`.
///
/// The [`CString::new`] method will actually check that the provided &[[u8]]
/// does not have 0 bytes in the middle, and return an error if it
@@ -1069,27 +1070,22 @@ impl CStr {
///
/// # Examples
///
- /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
+ /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8. The leading
+ /// `c` on the string literal denotes a `CStr`.
///
/// ```
/// use std::borrow::Cow;
- /// use std::ffi::CStr;
///
- /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
- /// .expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
+ /// assert_eq!(c"Hello World".to_string_lossy(), Cow::Borrowed("Hello World"));
/// ```
///
/// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
///
/// ```
/// use std::borrow::Cow;
- /// use std::ffi::CStr;
///
- /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
- /// .expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(
- /// cstr.to_string_lossy(),
+ /// c"Hello \xF0\x90\x80World".to_string_lossy(),
/// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
/// );
/// ```
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index aefb30463d33..297f52e756bc 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -23,28 +23,32 @@ use crate::str;
///
/// This type represents a borrowed reference to a nul-terminated
/// array of bytes. It can be constructed safely from a &[[u8]]
-/// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust &[str] by performing UTF-8 validation, or
-/// into an owned `CString`.
+/// slice, or unsafely from a raw `*const c_char`. It can be expressed as a
+/// literal in the form `c"Hello world"`.
+///
+/// The `CStr` can then be converted to a Rust &[str] by performing
+/// UTF-8 validation, or into an owned `CString`.
///
/// `&CStr` is to `CString` as &[str] is to `String`: the former
/// in each pair are borrowed references; the latter are owned
/// strings.
///
/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)`
-/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions.
-/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor
-/// to provide a safe interface to other consumers.
+/// notwithstanding) and should not be placed in the signatures of FFI functions.
+/// Instead, safe wrappers of FFI functions may leverage [`CStr::as_ptr`] and the unsafe
+/// [`CStr::from_ptr`] constructor to provide a safe interface to other consumers.
///
/// # Examples
///
/// Inspecting a foreign C string:
///
-/// ```ignore (extern-declaration)
+/// ```
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
+/// # /* Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn my_string() -> *const c_char; }
+/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
@@ -54,12 +58,14 @@ use crate::str;
///
/// Passing a Rust-originating C string:
///
-/// ```ignore (extern-declaration)
+/// ```
/// use std::ffi::{CString, CStr};
/// use std::os::raw::c_char;
///
/// fn work(data: &CStr) {
+/// # /* Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn work_with(data: *const c_char); }
+/// # */ unsafe extern "C" fn work_with(s: *const c_char) {}
///
/// unsafe { work_with(data.as_ptr()) }
/// }
@@ -70,11 +76,13 @@ use crate::str;
///
/// Converting a foreign C string into a Rust `String`:
///
-/// ```ignore (extern-declaration)
+/// ```
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
+/// # /* Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn my_string() -> *const c_char; }
+/// # */ unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
///
/// fn my_string_safe() -> String {
/// let cstr = unsafe { CStr::from_ptr(my_string()) };
@@ -241,16 +249,16 @@ impl CStr {
///
/// # Examples
///
- /// ```ignore (extern-declaration)
+ /// ```
/// use std::ffi::{c_char, CStr};
///
- /// extern "C" {
- /// fn my_string() -> *const c_char;
+ /// fn my_string() -> *const c_char {
+ /// c"hello".as_ptr()
/// }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
- /// println!("string returned: {}", slice.to_str().unwrap());
+ /// assert_eq!(slice.to_str().unwrap(), "hello");
/// }
/// ```
///
@@ -264,6 +272,8 @@ impl CStr {
/// BYTES.as_ptr().cast()
/// };
/// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
+ ///
+ /// assert_eq!(c"Hello, world!", HELLO);
/// ```
///
/// [valid]: core::ptr#safety
@@ -549,6 +559,7 @@ impl CStr {
///
/// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
/// assert!(empty_cstr.is_empty());
+ /// assert!(c"".is_empty());
/// # Ok(())
/// # }
/// ```
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d23764abe7a7..d1450bf12ce7 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -987,6 +987,7 @@ pub const unsafe fn assume(b: bool) {
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
+#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
pub const fn likely(b: bool) -> bool {
b
}
@@ -1006,6 +1007,7 @@ pub const fn likely(b: bool) -> bool {
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
+#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
pub const fn unlikely(b: bool) -> bool {
b
}
@@ -2469,6 +2471,7 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
#[rustc_do_not_const_check]
#[inline]
+#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 {
(ptr == other) as u8
}
@@ -2733,8 +2736,10 @@ pub const fn ub_checks() -> bool {
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_nounwind]
#[rustc_intrinsic]
+#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
- // const eval overrides this function, but runtime code should always just return null pointers.
+ // const eval overrides this function, but runtime code for now just returns null pointers.
+ // See .
crate::ptr::null_mut()
}
@@ -2752,7 +2757,10 @@ pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 {
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_nounwind]
#[rustc_intrinsic]
-pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
+#[cfg_attr(not(bootstrap), miri::intrinsic_fallback_checks_ub)]
+pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {
+ // Runtime NOP
+}
/// `ptr` must point to a vtable.
/// The intrinsic will return the size stored in that vtable.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 5dcef6389544..dcf68b36c7a2 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -186,7 +186,6 @@
#![feature(ptr_metadata)]
#![feature(set_ptr_value)]
#![feature(slice_ptr_get)]
-#![feature(split_at_checked)]
#![feature(str_internals)]
#![feature(str_split_inclusive_remainder)]
#![feature(str_split_remainder)]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 9effa279b48e..673144cb3282 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -77,7 +77,7 @@ macro_rules! uint_impl {
without modifying the original"]
#[inline(always)]
pub const fn count_ones(self) -> u32 {
- return intrinsics::ctpop(self as $ActualT);
+ return intrinsics::ctpop(self);
}
/// Returns the number of zeros in the binary representation of `self`.
@@ -636,6 +636,31 @@ macro_rules! uint_impl {
/// If you're just trying to avoid the panic in debug mode, then **do not**
/// use this. Instead, you're looking for [`wrapping_sub`].
///
+ /// If you find yourself writing code like this:
+ ///
+ /// ```
+ /// # let foo = 30_u32;
+ /// # let bar = 20;
+ /// if foo >= bar {
+ /// // SAFETY: just checked it will not overflow
+ /// let diff = unsafe { foo.unchecked_sub(bar) };
+ /// // ... use diff ...
+ /// }
+ /// ```
+ ///
+ /// Consider changing it to
+ ///
+ /// ```
+ /// # let foo = 30_u32;
+ /// # let bar = 20;
+ /// if let Some(diff) = foo.checked_sub(bar) {
+ /// // ... use diff ...
+ /// }
+ /// ```
+ ///
+ /// As that does exactly the same thing -- including telling the optimizer
+ /// that the subtraction cannot overflow -- but avoids needing `unsafe`.
+ ///
/// # Safety
///
/// This results in undefined behavior when
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index e9eeb3153307..73bb256518d8 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -358,6 +358,54 @@ impl *const T {
if self.is_null() { None } else { unsafe { Some(&*self) } }
}
+ /// Returns a shared reference to the value behind the pointer.
+ /// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead.
+ /// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead.
+ ///
+ /// [`as_ref`]: #method.as_ref
+ /// [`as_uninit_ref`]: #method.as_uninit_ref
+ ///
+ /// # Safety
+ ///
+ /// When calling this method, you have to ensure that all of the following is true:
+ ///
+ /// * The pointer must be properly aligned.
+ ///
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
+ ///
+ /// * The pointer must point to an initialized instance of `T`.
+ ///
+ /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+ /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+ /// In particular, while this reference exists, the memory the pointer points to must
+ /// not get mutated (except inside `UnsafeCell`).
+ ///
+ /// This applies even if the result of this method is unused!
+ /// (The part about being initialized is not yet fully decided, but until
+ /// it is, the only safe approach is to ensure that they are indeed initialized.)
+ ///
+ /// [the module documentation]: crate::ptr#safety
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_as_ref_unchecked)]
+ /// let ptr: *const u8 = &10u8 as *const u8;
+ ///
+ /// unsafe {
+ /// println!("We got back the value: {}!", ptr.as_ref_unchecked());
+ /// }
+ /// ```
+ // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
+ #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
+ #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+ #[inline]
+ #[must_use]
+ pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
+ // SAFETY: the caller must guarantee that `self` is valid for a reference
+ unsafe { &*self }
+ }
+
/// Returns `None` if the pointer is null, or else returns a shared reference to
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
/// that the value has to be initialized.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index c5a188dc7d4f..b67930503e01 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -367,6 +367,57 @@ impl *mut T {
if self.is_null() { None } else { unsafe { Some(&*self) } }
}
+ /// Returns a shared reference to the value behind the pointer.
+ /// If the pointer may be null or the value may be uninitialized, [`as_uninit_ref`] must be used instead.
+ /// If the pointer may be null, but the value is known to have been initialized, [`as_ref`] must be used instead.
+ ///
+ /// For the mutable counterpart see [`as_mut_unchecked`].
+ ///
+ /// [`as_ref`]: #method.as_ref
+ /// [`as_uninit_ref`]: #method.as_uninit_ref
+ /// [`as_mut_unchecked`]: #method.as_mut_unchecked
+ ///
+ /// # Safety
+ ///
+ /// When calling this method, you have to ensure that all of the following is true:
+ ///
+ /// * The pointer must be properly aligned.
+ ///
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
+ ///
+ /// * The pointer must point to an initialized instance of `T`.
+ ///
+ /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+ /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+ /// In particular, while this reference exists, the memory the pointer points to must
+ /// not get mutated (except inside `UnsafeCell`).
+ ///
+ /// This applies even if the result of this method is unused!
+ /// (The part about being initialized is not yet fully decided, but until
+ /// it is, the only safe approach is to ensure that they are indeed initialized.)
+ ///
+ /// [the module documentation]: crate::ptr#safety
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_as_ref_unchecked)]
+ /// let ptr: *mut u8 = &mut 10u8 as *mut u8;
+ ///
+ /// unsafe {
+ /// println!("We got back the value: {}!", ptr.as_ref_unchecked());
+ /// }
+ /// ```
+ // FIXME: mention it in the docs for `as_ref` and `as_uninit_ref` once stabilized.
+ #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
+ #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+ #[inline]
+ #[must_use]
+ pub const unsafe fn as_ref_unchecked<'a>(self) -> &'a T {
+ // SAFETY: the caller must guarantee that `self` is valid for a reference
+ unsafe { &*self }
+ }
+
/// Returns `None` if the pointer is null, or else returns a shared reference to
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
/// that the value has to be initialized.
@@ -688,6 +739,58 @@ impl *mut T {
if self.is_null() { None } else { unsafe { Some(&mut *self) } }
}
+ /// Returns a unique reference to the value behind the pointer.
+ /// If the pointer may be null or the value may be uninitialized, [`as_uninit_mut`] must be used instead.
+ /// If the pointer may be null, but the value is known to have been initialized, [`as_mut`] must be used instead.
+ ///
+ /// For the shared counterpart see [`as_ref_unchecked`].
+ ///
+ /// [`as_mut`]: #method.as_mut
+ /// [`as_uninit_mut`]: #method.as_uninit_mut
+ /// [`as_ref_unchecked`]: #method.as_mut_unchecked
+ ///
+ /// # Safety
+ ///
+ /// When calling this method, you have to ensure that all of the following is true:
+ ///
+ /// * The pointer must be properly aligned.
+ ///
+ /// * It must be "dereferenceable" in the sense defined in [the module documentation].
+ ///
+ /// * The pointer must point to an initialized instance of `T`.
+ ///
+ /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+ /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+ /// In particular, while this reference exists, the memory the pointer points to must
+ /// not get mutated (except inside `UnsafeCell`).
+ ///
+ /// This applies even if the result of this method is unused!
+ /// (The part about being initialized is not yet fully decided, but until
+ /// it is, the only safe approach is to ensure that they are indeed initialized.)
+ ///
+ /// [the module documentation]: crate::ptr#safety
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(ptr_as_ref_unchecked)]
+ /// let mut s = [1, 2, 3];
+ /// let ptr: *mut u32 = s.as_mut_ptr();
+ /// let first_value = unsafe { ptr.as_mut_unchecked() };
+ /// *first_value = 4;
+ /// # assert_eq!(s, [4, 2, 3]);
+ /// println!("{s:?}"); // It'll print: "[4, 2, 3]".
+ /// ```
+ // FIXME: mention it in the docs for `as_mut` and `as_uninit_mut` once stabilized.
+ #[unstable(feature = "ptr_as_ref_unchecked", issue = "122034")]
+ #[rustc_const_unstable(feature = "const_ptr_as_ref", issue = "91822")]
+ #[inline]
+ #[must_use]
+ pub const unsafe fn as_mut_unchecked<'a>(self) -> &'a mut T {
+ // SAFETY: the caller must guarantee that `self` is valid for a reference
+ unsafe { &mut *self }
+ }
+
/// Returns `None` if the pointer is null, or else returns a unique reference to
/// the value wrapped in `Some`. In contrast to [`as_mut`], this does not require
/// that the value has to be initialized.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 9c523fd6295d..de766a4b9774 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2051,8 +2051,6 @@ impl [T] {
/// # Examples
///
/// ```
- /// #![feature(split_at_checked)]
- ///
/// let v = [1, -2, 3, -4, 5, -6];
///
/// {
@@ -2075,8 +2073,8 @@ impl [T] {
///
/// assert_eq!(None, v.split_at_checked(7));
/// ```
- #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
- #[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
+ #[stable(feature = "split_at_checked", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "split_at_checked", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[must_use]
pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> {
@@ -2102,8 +2100,6 @@ impl [T] {
/// # Examples
///
/// ```
- /// #![feature(split_at_checked)]
- ///
/// let mut v = [1, 0, 3, 0, 5, 6];
///
/// if let Some((left, right)) = v.split_at_mut_checked(2) {
@@ -2116,8 +2112,8 @@ impl [T] {
///
/// assert_eq!(None, v.split_at_mut_checked(7));
/// ```
- #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
- #[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
+ #[stable(feature = "split_at_checked", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
#[inline]
#[must_use]
pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index adccbe02d46d..b6f65907d3c3 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -721,8 +721,6 @@ impl str {
/// # Examples
///
/// ```
- /// #![feature(split_at_checked)]
- ///
/// let s = "Per Martin-Löf";
///
/// let (first, last) = s.split_at_checked(3).unwrap();
@@ -734,7 +732,7 @@ impl str {
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
+ #[stable(feature = "split_at_checked", since = "CURRENT_RUSTC_VERSION")]
pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
@@ -761,8 +759,6 @@ impl str {
/// # Examples
///
/// ```
- /// #![feature(split_at_checked)]
- ///
/// let mut s = "Per Martin-Löf".to_string();
/// if let Some((first, last)) = s.split_at_mut_checked(3) {
/// first.make_ascii_uppercase();
@@ -776,7 +772,7 @@ impl str {
/// ```
#[inline]
#[must_use]
- #[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
+ #[stable(feature = "split_at_checked", since = "CURRENT_RUSTC_VERSION")]
pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(mid) {
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 78494b866b10..72f6a3b773bb 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -1437,10 +1437,10 @@ impl TryFromFloatSecsError {
const fn description(&self) -> &'static str {
match self.kind {
TryFromFloatSecsErrorKind::Negative => {
- "can not convert float seconds to Duration: value is negative"
+ "cannot convert float seconds to Duration: value is negative"
}
TryFromFloatSecsErrorKind::OverflowOrNan => {
- "can not convert float seconds to Duration: value is either too big or NaN"
+ "cannot convert float seconds to Duration: value is either too big or NaN"
}
}
}
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index dc0e302a8108..b98fbbf762fa 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -353,6 +353,12 @@ fn default_alloc_error_hook(layout: Layout) {
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {} bytes failed", layout.size());
} else {
+ // This is the default path taken on OOM, and the only path taken on stable with std.
+ // Crucially, it does *not* call any user-defined code, and therefore users do not have to
+ // worry about allocation failure causing reentrancy issues. That makes it different from
+ // the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is
+ // called when there is no `#[alloc_error_handler]`), which triggers a regular panic and
+ // thus can invoke a user-defined panic hook, executing arbitrary user-defined code.
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
}
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 59e118f81ab1..46f691d7b750 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -74,7 +74,7 @@ macro_rules! rtunwrap {
//
// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to
// `SIG_IGN`. Applications have good reasons to want a different behavior
-// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that
+// though, so there is a `-Zon-broken-pipe` compiler flag that
// can be used to select how `SIGPIPE` shall be setup (if changed at all) before
// `fn main()` is called. See
// for more info.
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index e2df57b1a1f5..7d271e6d2b65 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -67,7 +67,7 @@ mod task_queue {
pub mod wait_notify {
use crate::pin::Pin;
use crate::sync::Arc;
- use crate::sys_common::thread_parking::Parker;
+ use crate::sys::sync::Parker;
pub struct Notifier(Arc);
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index c392a0ea264b..6dd465a12ed4 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -30,8 +30,6 @@ pub mod thread;
pub mod thread_local_dtor;
#[path = "../unix/thread_local_key.rs"]
pub mod thread_local_key;
-#[path = "../unsupported/thread_parking.rs"]
-pub mod thread_parking;
#[allow(non_upper_case_globals)]
#[path = "../unix/time.rs"]
pub mod time;
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 562b00c2c01a..48b74df13843 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -30,8 +30,6 @@ pub mod stdio;
pub mod thread;
#[path = "../unsupported/thread_local_key.rs"]
pub mod thread_local_key;
-#[path = "../unsupported/thread_parking.rs"]
-pub mod thread_parking;
pub mod time;
mod helpers;
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 01d7fb31d7d6..1ac5729c02fd 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -55,8 +55,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// want!
//
// Hence, we set SIGPIPE to ignore when the program starts up in order
- // to prevent this problem. Add `#[unix_sigpipe = "..."]` above `fn main()` to
- // alter this behavior.
+ // to prevent this problem. Use `-Zon-broken-pipe=...` to alter this
+ // behavior.
reset_sigpipe(sigpipe);
stack_overflow::init();
@@ -190,7 +190,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
_ => unreachable!(),
};
if sigpipe_attr_specified {
- UNIX_SIGPIPE_ATTR_SPECIFIED.store(true, crate::sync::atomic::Ordering::Relaxed);
+ ON_BROKEN_PIPE_FLAG_USED.store(true, crate::sync::atomic::Ordering::Relaxed);
}
if let Some(handler) = handler {
rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
@@ -210,7 +210,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
target_os = "fuchsia",
target_os = "horizon",
)))]
-static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
+static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
crate::sync::atomic::AtomicBool::new(false);
#[cfg(not(any(
@@ -219,8 +219,8 @@ static UNIX_SIGPIPE_ATTR_SPECIFIED: crate::sync::atomic::AtomicBool =
target_os = "fuchsia",
target_os = "horizon",
)))]
-pub(crate) fn unix_sigpipe_attr_specified() -> bool {
- UNIX_SIGPIPE_ATTR_SPECIFIED.load(crate::sync::atomic::Ordering::Relaxed)
+pub(crate) fn on_broken_pipe_flag_used() -> bool {
+ ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
}
// SAFETY: must be called only once during runtime cleanup.
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 f2947161cd56..e2fca8c7e63d 100644
--- a/library/std/src/sys/pal/unix/process/process_unix.rs
+++ b/library/std/src/sys/pal/unix/process/process_unix.rs
@@ -353,11 +353,11 @@ impl Command {
// Inherit the signal mask from the parent rather than resetting it (i.e. do not call
// pthread_sigmask).
- // If #[unix_sigpipe] is specified, don't reset SIGPIPE to SIG_DFL.
- // If #[unix_sigpipe] is not specified, reset SIGPIPE to SIG_DFL for backward compatibility.
+ // If -Zon-broken-pipe is used, don't reset SIGPIPE to SIG_DFL.
+ // If -Zon-broken-pipe is not used, reset SIGPIPE to SIG_DFL for backward compatibility.
//
- // #[unix_sigpipe] is an opportunity to change the default here.
- if !crate::sys::pal::unix_sigpipe_attr_specified() {
+ // -Zon-broken-pipe is an opportunity to change the default here.
+ if !crate::sys::pal::on_broken_pipe_flag_used() {
#[cfg(target_os = "android")] // see issue #88585
{
let mut action: libc::sigaction = mem::zeroed();
@@ -450,7 +450,7 @@ impl Command {
) -> io::Result