commit
d0e77727b1
351 changed files with 2500 additions and 1463 deletions
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
|
||||
<a id="1.78.0-Internal-Changes"></a>
|
||||
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
7
compiler/rustc_abi/src/tests.rs
Normal file
7
compiler/rustc_abi/src/tests.rs
Normal file
|
@ -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());
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -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<rustc_parse_format::InnerSpan>,
|
||||
ty_span: Option<parse::InnerSpan>,
|
||||
fmt_span: Span,
|
||||
) {
|
||||
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -105,7 +105,7 @@ impl<'mir, 'tcx: 'mir> interpret::Machine<'mir, 'tcx> for DummyMachine {
|
|||
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
|
||||
_target: Option<BasicBlock>,
|
||||
_unwind: UnwindAction,
|
||||
) -> interpret::InterpResult<'tcx> {
|
||||
) -> interpret::InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
|
|
@ -459,16 +459,26 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||
dest: &MPlaceTy<'tcx, Self::Provenance>,
|
||||
target: Option<mir::BasicBlock>,
|
||||
_unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
|
||||
// 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(
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
|
|
|
@ -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<mir::BasicBlock>,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx>;
|
||||
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>>;
|
||||
|
||||
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
||||
fn assert_panic(
|
||||
|
|
|
@ -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(..)
|
||||
|
|
|
@ -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<str> 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<u128> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<AnonConst>,
|
||||
default: Option<&'hir AnonConst>,
|
||||
is_host_effect: bool,
|
||||
},
|
||||
}
|
||||
|
@ -1562,12 +1561,12 @@ impl fmt::Display for ConstContext {
|
|||
pub type Lit = Spanned<LitKind>;
|
||||
|
||||
#[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 <expr>`).
|
||||
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<AnonConst> 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<AnonConst>,
|
||||
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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:?}"),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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<Svh>) {
|
|||
|
||||
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<SystemTime
|
|||
string_to_timestamp(&directory_name[dash_indices[0] + 1..dash_indices[1]])
|
||||
}
|
||||
|
||||
fn timestamp_to_string(timestamp: SystemTime) -> 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<SystemTime, &'static str> {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Providers> = 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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::<Vec<_>>();
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ pub struct FunctionCoverageInfo {
|
|||
pub mappings: Vec<Mapping>,
|
||||
/// 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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:?}")?
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<Local>,
|
||||
storage_to_remove: BitSet<Local>,
|
||||
borrowed_locals: BitSet<Local>,
|
||||
borrowed_locals: &'a BitSet<Local>,
|
||||
copy_classes: &'a IndexSlice<Local, Local>,
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -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: &[] };
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Local, u32>,
|
||||
/// Set of SSA locals that are immutably borrowed.
|
||||
borrowed_locals: BitSet<Local>,
|
||||
}
|
||||
|
||||
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<Local> {
|
||||
&self.borrowed_locals
|
||||
}
|
||||
|
||||
/// Make a property uniform on a copy equivalence class by removing elements.
|
||||
pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
|
||||
// Consolidate to have a local iff all its copies are.
|
||||
|
@ -208,6 +235,8 @@ struct SsaVisitor<'tcx, 'a> {
|
|||
assignments: IndexVec<Local, Set1<DefLocation>>,
|
||||
assignment_order: Vec<Local>,
|
||||
direct_uses: IndexVec<Local, u32>,
|
||||
// Track locals that are immutably borrowed, so we can check their type is `Freeze` later.
|
||||
borrowed_locals: BitSet<Local>,
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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}`
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
|||
/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
|
||||
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 {
|
|||
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -1936,7 +1936,6 @@ symbols! {
|
|||
unit,
|
||||
universal_impl_trait,
|
||||
unix,
|
||||
unix_sigpipe,
|
||||
unlikely,
|
||||
unmarked_api,
|
||||
unnamed_fields,
|
||||
|
|
|
@ -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('_');
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
|
||||
) -> Result<Candidate<'tcx>, 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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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) -> <Self as ProofTreeVisitor<'tcx>>::Result,
|
||||
) -> <Self as ProofTreeVisitor<'tcx>>::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<PredicateObligation<'tcx>>;
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ pub struct InspectGoal<'a, 'tcx> {
|
|||
result: Result<Certainty, NoSolution>,
|
||||
evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>,
|
||||
normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
|
||||
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<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||
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<V: ProofTreeVisitor<'tcx>>(&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<InspectCandidate<'a, 'tcx>>,
|
||||
nested_goals: &mut Vec<inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>>,
|
||||
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<NormalizesToTermHack<'tcx>>,
|
||||
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<V: ProofTreeVisitor<'tcx>>(&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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ use crate::sync::Arc;
|
|||
/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
|
||||
/// example, you can build a `CString` straight out of a [`String`] or
|
||||
/// a <code>&[str]</code>, 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 <code>&[[u8]]</code>
|
||||
/// 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 <20>World")) as Cow<'_, str>
|
||||
/// );
|
||||
/// ```
|
||||
|
|
|
@ -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 <code>&[[u8]]</code>
|
||||
/// slice, or unsafely from a raw `*const c_char`. It can then be
|
||||
/// converted to a Rust <code>&[str]</code> 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 <code>&[str]</code> by performing
|
||||
/// UTF-8 validation, or into an owned `CString`.
|
||||
///
|
||||
/// `&CStr` is to `CString` as <code>&[str]</code> 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(())
|
||||
/// # }
|
||||
/// ```
|
||||
|
|
|
@ -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<T>(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 <https://github.com/rust-lang/rust/issues/93935>.
|
||||
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.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -358,6 +358,54 @@ impl<T: ?Sized> *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.
|
||||
|
|
|
@ -367,6 +367,57 @@ impl<T: ?Sized> *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<T: ?Sized> *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.
|
||||
|
|
|
@ -2051,8 +2051,6 @@ impl<T> [T] {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(split_at_checked)]
|
||||
///
|
||||
/// let v = [1, -2, 3, -4, 5, -6];
|
||||
///
|
||||
/// {
|
||||
|
@ -2075,8 +2073,8 @@ impl<T> [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> [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> [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])> {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <https://github.com/rust-lang/rust/issues/97889>
|
||||
// for more info.
|
||||
|
|
|
@ -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<Parker>);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<Option<Process>> {
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::sys::weak::weak;
|
||||
use crate::sys::{self, cvt_nz, unix_sigpipe_attr_specified};
|
||||
use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
|
||||
|
||||
if self.get_gid().is_some()
|
||||
|| self.get_uid().is_some()
|
||||
|
@ -612,11 +612,11 @@ impl Command {
|
|||
// Inherit the signal mask from this process rather than resetting it (i.e. do not call
|
||||
// posix_spawnattr_setsigmask).
|
||||
|
||||
// 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 !unix_sigpipe_attr_specified() {
|
||||
// -Zon-broken-pipe is an opportunity to change the default here.
|
||||
if !on_broken_pipe_flag_used() {
|
||||
let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
|
||||
cvt(sigemptyset(default_set.as_mut_ptr()))?;
|
||||
cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
// Only used on NetBSD. If other platforms start using id-based parking, use
|
||||
// separate modules for each platform.
|
||||
#![cfg(target_os = "netbsd")]
|
||||
|
||||
use crate::ffi::{c_int, c_void};
|
||||
use crate::ptr;
|
||||
use crate::time::Duration;
|
|
@ -1,24 +0,0 @@
|
|||
//! Thread parking on systems without futex support.
|
||||
|
||||
#![cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
all(target_os = "emscripten", target_feature = "atomics"),
|
||||
target_os = "freebsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "fuchsia",
|
||||
)))]
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_vendor = "apple", not(miri)))] {
|
||||
mod darwin;
|
||||
pub use darwin::Parker;
|
||||
} else if #[cfg(target_os = "netbsd")] {
|
||||
mod netbsd;
|
||||
pub use netbsd::{current, park, park_timeout, unpark, ThreadId};
|
||||
} else {
|
||||
mod pthread;
|
||||
pub use pthread::Parker;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,6 @@ pub mod thread;
|
|||
#[cfg(target_thread_local)]
|
||||
pub mod thread_local_dtor;
|
||||
pub mod thread_local_key;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
|
||||
mod common;
|
||||
|
|
|
@ -39,13 +39,6 @@ pub mod thread_local_dtor;
|
|||
pub mod thread_local_key;
|
||||
pub mod time;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_feature = "atomics"))] {
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -41,15 +41,6 @@ pub mod thread_local_key;
|
|||
#[path = "../wasi/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_feature = "atomics")] {
|
||||
compile_error!("The wasm32-wasip2 target does not support atomics");
|
||||
} else {
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
}
|
||||
}
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -50,8 +50,6 @@ cfg_if::cfg_if! {
|
|||
} else {
|
||||
#[path = "../unsupported/thread.rs"]
|
||||
pub mod thread;
|
||||
#[path = "../unsupported/thread_parking.rs"]
|
||||
pub mod thread_parking;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue