Merge from rustc
This commit is contained in:
commit
4481569b28
303 changed files with 3902 additions and 1663 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
@ -315,7 +315,7 @@ jobs:
|
||||||
NO_DEBUG_ASSERTIONS: 1
|
NO_DEBUG_ASSERTIONS: 1
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
DIST_REQUIRE_ALL_TOOLS: 1
|
DIST_REQUIRE_ALL_TOOLS: 1
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: dist-apple-various
|
- name: dist-apple-various
|
||||||
env:
|
env:
|
||||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
|
SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
|
||||||
|
@ -326,7 +326,7 @@ jobs:
|
||||||
NO_LLVM_ASSERTIONS: 1
|
NO_LLVM_ASSERTIONS: 1
|
||||||
NO_DEBUG_ASSERTIONS: 1
|
NO_DEBUG_ASSERTIONS: 1
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: dist-x86_64-apple-alt
|
- name: dist-x86_64-apple-alt
|
||||||
env:
|
env:
|
||||||
SCRIPT: "./x.py dist bootstrap --include-default-paths"
|
SCRIPT: "./x.py dist bootstrap --include-default-paths"
|
||||||
|
@ -337,7 +337,7 @@ jobs:
|
||||||
NO_LLVM_ASSERTIONS: 1
|
NO_LLVM_ASSERTIONS: 1
|
||||||
NO_DEBUG_ASSERTIONS: 1
|
NO_DEBUG_ASSERTIONS: 1
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: x86_64-apple-1
|
- name: x86_64-apple-1
|
||||||
env:
|
env:
|
||||||
SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps"
|
SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps"
|
||||||
|
@ -348,7 +348,7 @@ jobs:
|
||||||
NO_LLVM_ASSERTIONS: 1
|
NO_LLVM_ASSERTIONS: 1
|
||||||
NO_DEBUG_ASSERTIONS: 1
|
NO_DEBUG_ASSERTIONS: 1
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: x86_64-apple-2
|
- name: x86_64-apple-2
|
||||||
env:
|
env:
|
||||||
SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps"
|
SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps"
|
||||||
|
@ -359,7 +359,7 @@ jobs:
|
||||||
NO_LLVM_ASSERTIONS: 1
|
NO_LLVM_ASSERTIONS: 1
|
||||||
NO_DEBUG_ASSERTIONS: 1
|
NO_DEBUG_ASSERTIONS: 1
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: dist-aarch64-apple
|
- name: dist-aarch64-apple
|
||||||
env:
|
env:
|
||||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
|
SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2"
|
||||||
|
@ -374,7 +374,7 @@ jobs:
|
||||||
NO_OVERFLOW_CHECKS: 1
|
NO_OVERFLOW_CHECKS: 1
|
||||||
DIST_REQUIRE_ALL_TOOLS: 1
|
DIST_REQUIRE_ALL_TOOLS: 1
|
||||||
JEMALLOC_SYS_WITH_LG_PAGE: 14
|
JEMALLOC_SYS_WITH_LG_PAGE: 14
|
||||||
os: macos-latest
|
os: macos-13
|
||||||
- name: x86_64-msvc
|
- name: x86_64-msvc
|
||||||
env:
|
env:
|
||||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
||||||
|
|
|
@ -3021,7 +3021,6 @@ dependencies = [
|
||||||
name = "rls"
|
name = "rls"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4234,6 +4233,7 @@ dependencies = [
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
"rustc_target",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1300,14 +1300,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssocItemKind::Type(box TyAlias {
|
AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
|
||||||
generics,
|
|
||||||
where_clauses,
|
|
||||||
where_predicates_split,
|
|
||||||
bounds,
|
|
||||||
ty,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
if ty.is_none() {
|
if ty.is_none() {
|
||||||
self.session.emit_err(errors::AssocTypeWithoutBody {
|
self.session.emit_err(errors::AssocTypeWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
|
@ -1315,18 +1308,26 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
self.check_type_no_bounds(bounds, "`impl`s");
|
self.check_type_no_bounds(bounds, "`impl`s");
|
||||||
if ty.is_some() {
|
|
||||||
self.check_gat_where(
|
|
||||||
item.id,
|
|
||||||
generics.where_clause.predicates.split_at(*where_predicates_split).0,
|
|
||||||
*where_clauses,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let AssocItemKind::Type(box TyAlias {
|
||||||
|
generics,
|
||||||
|
where_clauses,
|
||||||
|
where_predicates_split,
|
||||||
|
ty: Some(_),
|
||||||
|
..
|
||||||
|
}) = &item.kind
|
||||||
|
{
|
||||||
|
self.check_gat_where(
|
||||||
|
item.id,
|
||||||
|
generics.where_clause.predicates.split_at(*where_predicates_split).0,
|
||||||
|
*where_clauses,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
|
||||||
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
||||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct UseFactsExtractor<'me, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Visitor to walk through the MIR and extract point-wise facts
|
// A Visitor to walk through the MIR and extract point-wise facts
|
||||||
impl UseFactsExtractor<'_, '_> {
|
impl<'tcx> UseFactsExtractor<'_, 'tcx> {
|
||||||
fn location_to_index(&self, location: Location) -> LocationIndex {
|
fn location_to_index(&self, location: Location) -> LocationIndex {
|
||||||
self.location_table.mid_index(location)
|
self.location_table.mid_index(location)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ impl UseFactsExtractor<'_, '_> {
|
||||||
self.path_accessed_at_base.push((path, self.location_to_index(location)));
|
self.path_accessed_at_base.push((path, self.location_to_index(location)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
|
fn place_to_mpi(&self, place: &Place<'tcx>) -> Option<MovePathIndex> {
|
||||||
match self.move_data.rev_lookup.find(place.as_ref()) {
|
match self.move_data.rev_lookup.find(place.as_ref()) {
|
||||||
LookupResult::Exact(mpi) => Some(mpi),
|
LookupResult::Exact(mpi) => Some(mpi),
|
||||||
LookupResult::Parent(mmpi) => mmpi,
|
LookupResult::Parent(mmpi) => mmpi,
|
||||||
|
|
|
@ -290,7 +290,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let llval = unsafe {
|
let llval = unsafe {
|
||||||
llvm::LLVMRustConstInBoundsGEP2(
|
llvm::LLVMConstInBoundsGEP2(
|
||||||
self.type_i8(),
|
self.type_i8(),
|
||||||
self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
|
self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
|
||||||
&self.const_usize(offset.bytes()),
|
&self.const_usize(offset.bytes()),
|
||||||
|
@ -320,7 +320,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||||
|
|
||||||
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
|
fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value {
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustConstInBoundsGEP2(
|
llvm::LLVMConstInBoundsGEP2(
|
||||||
self.type_i8(),
|
self.type_i8(),
|
||||||
self.const_bitcast(base_addr, self.type_i8p()),
|
self.const_bitcast(base_addr, self.type_i8p()),
|
||||||
&self.const_usize(offset.bytes()),
|
&self.const_usize(offset.bytes()),
|
||||||
|
|
|
@ -1155,7 +1155,7 @@ extern "C" {
|
||||||
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
|
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
|
||||||
|
|
||||||
// Constant expressions
|
// Constant expressions
|
||||||
pub fn LLVMRustConstInBoundsGEP2<'a>(
|
pub fn LLVMConstInBoundsGEP2<'a>(
|
||||||
ty: &'a Type,
|
ty: &'a Type,
|
||||||
ConstantVal: &'a Value,
|
ConstantVal: &'a Value,
|
||||||
ConstantIndices: *const &'a Value,
|
ConstantIndices: *const &'a Value,
|
||||||
|
|
|
@ -12,7 +12,6 @@ use object::{
|
||||||
|
|
||||||
use snap::write::FrameEncoder;
|
use snap::write::FrameEncoder;
|
||||||
|
|
||||||
use object::elf::NT_GNU_PROPERTY_TYPE_0;
|
|
||||||
use rustc_data_structures::memmap::Mmap;
|
use rustc_data_structures::memmap::Mmap;
|
||||||
use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
|
use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
|
||||||
use rustc_metadata::fs::METADATA_FILENAME;
|
use rustc_metadata::fs::METADATA_FILENAME;
|
||||||
|
@ -124,7 +123,7 @@ fn add_gnu_property_note(
|
||||||
let mut data: Vec<u8> = Vec::new();
|
let mut data: Vec<u8> = Vec::new();
|
||||||
let n_namsz: u32 = 4; // Size of the n_name field
|
let n_namsz: u32 = 4; // Size of the n_name field
|
||||||
let n_descsz: u32 = 16; // Size of the n_desc field
|
let n_descsz: u32 = 16; // Size of the n_desc field
|
||||||
let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
|
let n_type: u32 = object::elf::NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
|
||||||
let header_values = [n_namsz, n_descsz, n_type];
|
let header_values = [n_namsz, n_descsz, n_type];
|
||||||
header_values.iter().for_each(|v| {
|
header_values.iter().for_each(|v| {
|
||||||
data.extend_from_slice(&match endianness {
|
data.extend_from_slice(&match endianness {
|
||||||
|
@ -134,8 +133,8 @@ fn add_gnu_property_note(
|
||||||
});
|
});
|
||||||
data.extend_from_slice(b"GNU\0"); // Owner of the program property note
|
data.extend_from_slice(b"GNU\0"); // Owner of the program property note
|
||||||
let pr_type: u32 = match architecture {
|
let pr_type: u32 = match architecture {
|
||||||
Architecture::X86_64 => 0xc0000002,
|
Architecture::X86_64 => object::elf::GNU_PROPERTY_X86_FEATURE_1_AND,
|
||||||
Architecture::Aarch64 => 0xc0000000,
|
Architecture::Aarch64 => object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let pr_datasz: u32 = 4; //size of the pr_data field
|
let pr_datasz: u32 = 4; //size of the pr_data field
|
||||||
|
@ -243,8 +242,16 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||||
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
|
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
|
||||||
_ => elf::EF_MIPS_ARCH_32R2,
|
_ => elf::EF_MIPS_ARCH_32R2,
|
||||||
};
|
};
|
||||||
// The only ABI LLVM supports for 32-bit MIPS CPUs is o32.
|
|
||||||
let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch;
|
let mut e_flags = elf::EF_MIPS_CPIC | arch;
|
||||||
|
|
||||||
|
// If the ABI is explicitly given, use it or default to O32.
|
||||||
|
match sess.target.options.llvm_abiname.to_lowercase().as_str() {
|
||||||
|
"n32" => e_flags |= elf::EF_MIPS_ABI2,
|
||||||
|
"o32" => e_flags |= elf::EF_MIPS_ABI_O32,
|
||||||
|
_ => e_flags |= elf::EF_MIPS_ABI_O32,
|
||||||
|
};
|
||||||
|
|
||||||
if sess.target.options.relocation_model != RelocModel::Static {
|
if sess.target.options.relocation_model != RelocModel::Static {
|
||||||
e_flags |= elf::EF_MIPS_PIC;
|
e_flags |= elf::EF_MIPS_PIC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
use crate::errors::{LongRunning, LongRunningWarn};
|
use crate::errors::{LongRunning, LongRunningWarn};
|
||||||
use crate::interpret::{
|
use crate::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
|
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
|
||||||
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
|
||||||
};
|
};
|
||||||
use crate::{errors, fluent_generated as fluent};
|
use crate::{errors, fluent_generated as fluent};
|
||||||
|
@ -201,7 +201,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
fn hook_special_const_fn(
|
fn hook_special_const_fn(
|
||||||
&mut self,
|
&mut self,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
args: &[OpTy<'tcx>],
|
args: &[FnArg<'tcx>],
|
||||||
dest: &PlaceTy<'tcx>,
|
dest: &PlaceTy<'tcx>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
|
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
|
||||||
|
@ -210,6 +210,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
if Some(def_id) == self.tcx.lang_items().panic_display()
|
if Some(def_id) == self.tcx.lang_items().panic_display()
|
||||||
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
|
||||||
{
|
{
|
||||||
|
let args = self.copy_fn_args(args)?;
|
||||||
// &str or &&str
|
// &str or &&str
|
||||||
assert!(args.len() == 1);
|
assert!(args.len() == 1);
|
||||||
|
|
||||||
|
@ -236,8 +237,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
|
|
||||||
return Ok(Some(new_instance));
|
return Ok(Some(new_instance));
|
||||||
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
|
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
|
||||||
|
let args = self.copy_fn_args(args)?;
|
||||||
// For align_offset, we replace the function call if the pointer has no address.
|
// For align_offset, we replace the function call if the pointer has no address.
|
||||||
match self.align_offset(instance, args, dest, ret)? {
|
match self.align_offset(instance, &args, dest, ret)? {
|
||||||
ControlFlow::Continue(()) => return Ok(Some(instance)),
|
ControlFlow::Continue(()) => return Ok(Some(instance)),
|
||||||
ControlFlow::Break(()) => return Ok(None),
|
ControlFlow::Break(()) => return Ok(None),
|
||||||
}
|
}
|
||||||
|
@ -293,7 +295,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
|
||||||
self.eval_fn_call(
|
self.eval_fn_call(
|
||||||
FnVal::Instance(instance),
|
FnVal::Instance(instance),
|
||||||
(CallAbi::Rust, fn_abi),
|
(CallAbi::Rust, fn_abi),
|
||||||
&[addr, align],
|
&[FnArg::Copy(addr), FnArg::Copy(align)],
|
||||||
/* with_caller_location = */ false,
|
/* with_caller_location = */ false,
|
||||||
dest,
|
dest,
|
||||||
ret,
|
ret,
|
||||||
|
@ -427,7 +429,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
_abi: CallAbi,
|
_abi: CallAbi,
|
||||||
args: &[OpTy<'tcx>],
|
args: &[FnArg<'tcx>],
|
||||||
dest: &PlaceTy<'tcx>,
|
dest: &PlaceTy<'tcx>,
|
||||||
ret: Option<mir::BasicBlock>,
|
ret: Option<mir::BasicBlock>,
|
||||||
_unwind: mir::UnwindAction, // unwinding is not supported in consts
|
_unwind: mir::UnwindAction, // unwinding is not supported in consts
|
||||||
|
|
|
@ -682,11 +682,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
return_to_block: StackPopCleanup,
|
return_to_block: StackPopCleanup,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
trace!("body: {:#?}", body);
|
trace!("body: {:#?}", body);
|
||||||
// Clobber previous return place contents, nobody is supposed to be able to see them any more
|
// First push a stack frame so we have access to the local substs
|
||||||
// This also checks dereferenceable, but not align. We rely on all constructed places being
|
|
||||||
// sufficiently aligned (in particular we rely on `deref_operand` checking alignment).
|
|
||||||
self.write_uninit(return_place)?;
|
|
||||||
// first push a stack frame so we have access to the local substs
|
|
||||||
let pre_frame = Frame {
|
let pre_frame = Frame {
|
||||||
body,
|
body,
|
||||||
loc: Right(body.span), // Span used for errors caused during preamble.
|
loc: Right(body.span), // Span used for errors caused during preamble.
|
||||||
|
@ -805,6 +801,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
throw_ub_custom!(fluent::const_eval_unwind_past_top);
|
throw_ub_custom!(fluent::const_eval_unwind_past_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M::before_stack_pop(self, self.frame())?;
|
||||||
|
|
||||||
// Copy return value. Must of course happen *before* we deallocate the locals.
|
// Copy return value. Must of course happen *before* we deallocate the locals.
|
||||||
let copy_ret_result = if !unwinding {
|
let copy_ret_result = if !unwinding {
|
||||||
let op = self
|
let op = self
|
||||||
|
|
|
@ -30,7 +30,7 @@ use super::{
|
||||||
use crate::const_eval;
|
use crate::const_eval;
|
||||||
use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer};
|
use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer};
|
||||||
|
|
||||||
pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
|
pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
|
||||||
'mir,
|
'mir,
|
||||||
'tcx,
|
'tcx,
|
||||||
MemoryKind = T,
|
MemoryKind = T,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
use crate::const_eval::CheckAlignment;
|
use crate::const_eval::CheckAlignment;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
|
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
|
||||||
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ pub trait AllocMap<K: Hash + Eq, V> {
|
||||||
|
|
||||||
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
||||||
/// and some use case dependent behaviour can instead be applied.
|
/// and some use case dependent behaviour can instead be applied.
|
||||||
pub trait Machine<'mir, 'tcx>: Sized {
|
pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
||||||
type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
|
type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
instance: ty::Instance<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
abi: CallAbi,
|
abi: CallAbi,
|
||||||
args: &[OpTy<'tcx, Self::Provenance>],
|
args: &[FnArg<'tcx, Self::Provenance>],
|
||||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
unwind: mir::UnwindAction,
|
unwind: mir::UnwindAction,
|
||||||
|
@ -194,7 +194,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
fn_val: Self::ExtraFnVal,
|
fn_val: Self::ExtraFnVal,
|
||||||
abi: CallAbi,
|
abi: CallAbi,
|
||||||
args: &[OpTy<'tcx, Self::Provenance>],
|
args: &[FnArg<'tcx, Self::Provenance>],
|
||||||
destination: &PlaceTy<'tcx, Self::Provenance>,
|
destination: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
unwind: mir::UnwindAction,
|
unwind: mir::UnwindAction,
|
||||||
|
@ -418,6 +418,18 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called on places used for in-place function argument and return value handling.
|
||||||
|
///
|
||||||
|
/// These places need to be protected to make sure the program cannot tell whether the
|
||||||
|
/// argument/return value was actually copied or passed in-place..
|
||||||
|
fn protect_in_place_function_argument(
|
||||||
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
|
place: &PlaceTy<'tcx, Self::Provenance>,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
// Without an aliasing model, all we can do is put `Uninit` into the place.
|
||||||
|
ecx.write_uninit(place)
|
||||||
|
}
|
||||||
|
|
||||||
/// Called immediately before a new stack frame gets pushed.
|
/// Called immediately before a new stack frame gets pushed.
|
||||||
fn init_frame_extra(
|
fn init_frame_extra(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
|
@ -439,6 +451,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called just before the return value is copied to the caller-provided return place.
|
||||||
|
fn before_stack_pop(
|
||||||
|
_ecx: &InterpCx<'mir, 'tcx, Self>,
|
||||||
|
_frame: &Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
|
||||||
|
) -> InterpResult<'tcx> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
|
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
|
||||||
/// The `locals` have already been destroyed!
|
/// The `locals` have already been destroyed!
|
||||||
fn after_stack_pop(
|
fn after_stack_pop(
|
||||||
|
@ -484,7 +504,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||||
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
_ecx: &mut InterpCx<$mir, $tcx, Self>,
|
||||||
fn_val: !,
|
fn_val: !,
|
||||||
_abi: CallAbi,
|
_abi: CallAbi,
|
||||||
_args: &[OpTy<$tcx>],
|
_args: &[FnArg<$tcx>],
|
||||||
_destination: &PlaceTy<$tcx, Self::Provenance>,
|
_destination: &PlaceTy<$tcx, Self::Provenance>,
|
||||||
_target: Option<mir::BasicBlock>,
|
_target: Option<mir::BasicBlock>,
|
||||||
_unwind: mir::UnwindAction,
|
_unwind: mir::UnwindAction,
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP
|
||||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||||
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
|
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
|
||||||
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
|
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
|
||||||
|
pub use self::terminator::FnArg;
|
||||||
pub use self::validity::{CtfeValidationMode, RefTracking};
|
pub use self::validity::{CtfeValidationMode, RefTracking};
|
||||||
pub use self::visitor::{MutValueVisitor, Value, ValueVisitor};
|
pub use self::visitor::{MutValueVisitor, Value, ValueVisitor};
|
||||||
|
|
||||||
|
|
|
@ -575,14 +575,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(op)
|
Ok(op)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a bunch of operands at once
|
|
||||||
pub(super) fn eval_operands(
|
|
||||||
&self,
|
|
||||||
ops: &[mir::Operand<'tcx>],
|
|
||||||
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
|
|
||||||
ops.iter().map(|op| self.eval_operand(op, None)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_ty_constant(
|
fn eval_ty_constant(
|
||||||
&self,
|
&self,
|
||||||
val: ty::Const<'tcx>,
|
val: ty::Const<'tcx>,
|
||||||
|
|
|
@ -328,7 +328,8 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let mplace = MemPlace { ptr: ptr.to_pointer(self)?, meta };
|
let mplace = MemPlace { ptr: ptr.to_pointer(self)?, meta };
|
||||||
// When deref'ing a pointer, the *static* alignment given by the type is what matters.
|
// `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
|
||||||
|
// we hence can't call `size_and_align_of` since that asserts more validity than we want.
|
||||||
let align = layout.align.abi;
|
let align = layout.align.abi;
|
||||||
Ok(MPlaceTy { mplace, layout, align })
|
Ok(MPlaceTy { mplace, layout, align })
|
||||||
}
|
}
|
||||||
|
@ -354,34 +355,37 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn get_place_alloc(
|
pub(super) fn get_place_alloc(
|
||||||
&self,
|
&self,
|
||||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||||
{
|
{
|
||||||
assert!(place.layout.is_sized());
|
let (size, _align) = self
|
||||||
assert!(!place.meta.has_meta());
|
.size_and_align_of_mplace(&mplace)?
|
||||||
let size = place.layout.size;
|
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
|
||||||
self.get_ptr_alloc(place.ptr, size, place.align)
|
// Due to packed places, only `mplace.align` matters.
|
||||||
|
self.get_ptr_alloc(mplace.ptr, size, mplace.align)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn get_place_alloc_mut(
|
pub(super) fn get_place_alloc_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
|
||||||
{
|
{
|
||||||
assert!(place.layout.is_sized());
|
let (size, _align) = self
|
||||||
assert!(!place.meta.has_meta());
|
.size_and_align_of_mplace(&mplace)?
|
||||||
let size = place.layout.size;
|
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
|
||||||
self.get_ptr_alloc_mut(place.ptr, size, place.align)
|
// Due to packed places, only `mplace.align` matters.
|
||||||
|
self.get_ptr_alloc_mut(mplace.ptr, size, mplace.align)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if this mplace is dereferenceable and sufficiently aligned.
|
/// Check if this mplace is dereferenceable and sufficiently aligned.
|
||||||
pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
pub fn check_mplace(&self, mplace: MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
|
||||||
let (size, align) = self
|
let (size, _align) = self
|
||||||
.size_and_align_of_mplace(&mplace)?
|
.size_and_align_of_mplace(&mplace)?
|
||||||
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
|
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
|
||||||
assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
|
// Due to packed places, only `mplace.align` matters.
|
||||||
let align = if M::enforce_alignment(self).should_check() { align } else { Align::ONE };
|
let align =
|
||||||
|
if M::enforce_alignment(self).should_check() { mplace.align } else { Align::ONE };
|
||||||
self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
|
self.check_ptr_access_align(mplace.ptr, size, align, CheckInAllocMsg::DerefTest)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use rustc_ast::ast::InlineAsmOptions;
|
use rustc_ast::ast::InlineAsmOptions;
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
|
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
mir,
|
mir,
|
||||||
|
@ -12,12 +13,63 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
|
AllocId, FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy,
|
||||||
PlaceTy, Scalar, StackPopCleanup,
|
Operand, PlaceTy, Provenance, Scalar, StackPopCleanup,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
use crate::fluent_generated as fluent;
|
||||||
|
|
||||||
|
/// An argment passed to a function.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum FnArg<'tcx, Prov: Provenance = AllocId> {
|
||||||
|
/// Pass a copy of the given operand.
|
||||||
|
Copy(OpTy<'tcx, Prov>),
|
||||||
|
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
|
||||||
|
/// make the place inaccessible for the duration of the function call.
|
||||||
|
InPlace(PlaceTy<'tcx, Prov>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, Prov: Provenance> FnArg<'tcx, Prov> {
|
||||||
|
pub fn layout(&self) -> &TyAndLayout<'tcx> {
|
||||||
|
match self {
|
||||||
|
FnArg::Copy(op) => &op.layout,
|
||||||
|
FnArg::InPlace(place) => &place.layout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
|
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
|
||||||
|
/// original memory occurs.
|
||||||
|
pub fn copy_fn_arg(
|
||||||
|
&self,
|
||||||
|
arg: &FnArg<'tcx, M::Provenance>,
|
||||||
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||||
|
match arg {
|
||||||
|
FnArg::Copy(op) => Ok(op.clone()),
|
||||||
|
FnArg::InPlace(place) => self.place_to_op(&place),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make a copy of the given fn_args. Any `InPlace` are degenerated to copies, no protection of the
|
||||||
|
/// original memory occurs.
|
||||||
|
pub fn copy_fn_args(
|
||||||
|
&self,
|
||||||
|
args: &[FnArg<'tcx, M::Provenance>],
|
||||||
|
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
|
||||||
|
args.iter().map(|fn_arg| self.copy_fn_arg(fn_arg)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fn_arg_field(
|
||||||
|
&mut self,
|
||||||
|
arg: &FnArg<'tcx, M::Provenance>,
|
||||||
|
field: usize,
|
||||||
|
) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> {
|
||||||
|
Ok(match arg {
|
||||||
|
FnArg::Copy(op) => FnArg::Copy(self.operand_field(op, field)?),
|
||||||
|
FnArg::InPlace(place) => FnArg::InPlace(self.place_field(place, field)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn eval_terminator(
|
pub(super) fn eval_terminator(
|
||||||
&mut self,
|
&mut self,
|
||||||
terminator: &mir::Terminator<'tcx>,
|
terminator: &mir::Terminator<'tcx>,
|
||||||
|
@ -68,14 +120,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
let old_stack = self.frame_idx();
|
let old_stack = self.frame_idx();
|
||||||
let old_loc = self.frame().loc;
|
let old_loc = self.frame().loc;
|
||||||
let func = self.eval_operand(func, None)?;
|
let func = self.eval_operand(func, None)?;
|
||||||
let args = self.eval_operands(args)?;
|
let args = self.eval_fn_call_arguments(args)?;
|
||||||
|
|
||||||
let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
|
let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
|
||||||
let fn_sig =
|
let fn_sig =
|
||||||
self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
|
self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
|
||||||
let extra_args = &args[fn_sig.inputs().len()..];
|
let extra_args = &args[fn_sig.inputs().len()..];
|
||||||
let extra_args =
|
let extra_args =
|
||||||
self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty));
|
self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout().ty));
|
||||||
|
|
||||||
let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
|
let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() {
|
||||||
ty::FnPtr(_sig) => {
|
ty::FnPtr(_sig) => {
|
||||||
|
@ -185,6 +237,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate the arguments of a function call
|
||||||
|
pub(super) fn eval_fn_call_arguments(
|
||||||
|
&mut self,
|
||||||
|
ops: &[mir::Operand<'tcx>],
|
||||||
|
) -> InterpResult<'tcx, Vec<FnArg<'tcx, M::Provenance>>> {
|
||||||
|
ops.iter()
|
||||||
|
.map(|op| {
|
||||||
|
Ok(match op {
|
||||||
|
mir::Operand::Move(place) => FnArg::InPlace(self.eval_place(*place)?),
|
||||||
|
_ => FnArg::Copy(self.eval_operand(op, None)?),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn check_argument_compat(
|
fn check_argument_compat(
|
||||||
caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||||
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||||
|
@ -275,7 +342,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
fn pass_argument<'x, 'y>(
|
fn pass_argument<'x, 'y>(
|
||||||
&mut self,
|
&mut self,
|
||||||
caller_args: &mut impl Iterator<
|
caller_args: &mut impl Iterator<
|
||||||
Item = (&'x OpTy<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
|
Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
|
||||||
>,
|
>,
|
||||||
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
|
||||||
callee_arg: &PlaceTy<'tcx, M::Provenance>,
|
callee_arg: &PlaceTy<'tcx, M::Provenance>,
|
||||||
|
@ -295,21 +362,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// Now, check
|
// Now, check
|
||||||
if !Self::check_argument_compat(caller_abi, callee_abi) {
|
if !Self::check_argument_compat(caller_abi, callee_abi) {
|
||||||
let callee_ty = format!("{}", callee_arg.layout.ty);
|
let callee_ty = format!("{}", callee_arg.layout.ty);
|
||||||
let caller_ty = format!("{}", caller_arg.layout.ty);
|
let caller_ty = format!("{}", caller_arg.layout().ty);
|
||||||
throw_ub_custom!(
|
throw_ub_custom!(
|
||||||
fluent::const_eval_incompatible_types,
|
fluent::const_eval_incompatible_types,
|
||||||
callee_ty = callee_ty,
|
callee_ty = callee_ty,
|
||||||
caller_ty = caller_ty,
|
caller_ty = caller_ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// We work with a copy of the argument for now; if this is in-place argument passing, we
|
||||||
|
// will later protect the source it comes from. This means the callee cannot observe if we
|
||||||
|
// did in-place of by-copy argument passing, except for pointer equality tests.
|
||||||
|
let caller_arg_copy = self.copy_fn_arg(&caller_arg)?;
|
||||||
// Special handling for unsized parameters.
|
// Special handling for unsized parameters.
|
||||||
if caller_arg.layout.is_unsized() {
|
if caller_arg_copy.layout.is_unsized() {
|
||||||
// `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way.
|
// `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way.
|
||||||
assert_eq!(caller_arg.layout.ty, callee_arg.layout.ty);
|
assert_eq!(caller_arg_copy.layout.ty, callee_arg.layout.ty);
|
||||||
// We have to properly pre-allocate the memory for the callee.
|
// We have to properly pre-allocate the memory for the callee.
|
||||||
// So let's tear down some wrappers.
|
// So let's tear down some abstractions.
|
||||||
// This all has to be in memory, there are no immediate unsized values.
|
// This all has to be in memory, there are no immediate unsized values.
|
||||||
let src = caller_arg.assert_mem_place();
|
let src = caller_arg_copy.assert_mem_place();
|
||||||
// The destination cannot be one of these "spread args".
|
// The destination cannot be one of these "spread args".
|
||||||
let (dest_frame, dest_local) = callee_arg.assert_local();
|
let (dest_frame, dest_local) = callee_arg.assert_local();
|
||||||
// We are just initializing things, so there can't be anything here yet.
|
// We are just initializing things, so there can't be anything here yet.
|
||||||
|
@ -331,7 +402,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
|
// FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
|
||||||
// is true for all `copy_op`, but there are a lot of special cases for argument passing
|
// is true for all `copy_op`, but there are a lot of special cases for argument passing
|
||||||
// specifically.)
|
// specifically.)
|
||||||
self.copy_op(&caller_arg, callee_arg, /*allow_transmute*/ true)
|
self.copy_op(&caller_arg_copy, callee_arg, /*allow_transmute*/ true)?;
|
||||||
|
// If this was an in-place pass, protect the place it comes from for the duration of the call.
|
||||||
|
if let FnArg::InPlace(place) = caller_arg {
|
||||||
|
M::protect_in_place_function_argument(self, place)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this function -- pushing the stack frame and initializing the arguments.
|
/// Call this function -- pushing the stack frame and initializing the arguments.
|
||||||
|
@ -346,7 +422,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
&mut self,
|
&mut self,
|
||||||
fn_val: FnVal<'tcx, M::ExtraFnVal>,
|
fn_val: FnVal<'tcx, M::ExtraFnVal>,
|
||||||
(caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
|
(caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>),
|
||||||
args: &[OpTy<'tcx, M::Provenance>],
|
args: &[FnArg<'tcx, M::Provenance>],
|
||||||
with_caller_location: bool,
|
with_caller_location: bool,
|
||||||
destination: &PlaceTy<'tcx, M::Provenance>,
|
destination: &PlaceTy<'tcx, M::Provenance>,
|
||||||
target: Option<mir::BasicBlock>,
|
target: Option<mir::BasicBlock>,
|
||||||
|
@ -372,8 +448,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
match instance.def {
|
match instance.def {
|
||||||
ty::InstanceDef::Intrinsic(def_id) => {
|
ty::InstanceDef::Intrinsic(def_id) => {
|
||||||
assert!(self.tcx.is_intrinsic(def_id));
|
assert!(self.tcx.is_intrinsic(def_id));
|
||||||
// caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
|
// FIXME: Should `InPlace` arguments be reset to uninit?
|
||||||
M::call_intrinsic(self, instance, args, destination, target, unwind)
|
M::call_intrinsic(
|
||||||
|
self,
|
||||||
|
instance,
|
||||||
|
&self.copy_fn_args(args)?,
|
||||||
|
destination,
|
||||||
|
target,
|
||||||
|
unwind,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ty::InstanceDef::VTableShim(..)
|
ty::InstanceDef::VTableShim(..)
|
||||||
| ty::InstanceDef::ReifyShim(..)
|
| ty::InstanceDef::ReifyShim(..)
|
||||||
|
@ -428,7 +511,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
"caller ABI: {:?}, args: {:#?}",
|
"caller ABI: {:?}, args: {:#?}",
|
||||||
caller_abi,
|
caller_abi,
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(|arg| (arg.layout.ty, format!("{:?}", **arg)))
|
.map(|arg| (
|
||||||
|
arg.layout().ty,
|
||||||
|
match arg {
|
||||||
|
FnArg::Copy(op) => format!("copy({:?})", *op),
|
||||||
|
FnArg::InPlace(place) => format!("in-place({:?})", *place),
|
||||||
|
}
|
||||||
|
))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
trace!(
|
trace!(
|
||||||
|
@ -449,7 +538,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// last incoming argument. These two iterators do not have the same type,
|
// last incoming argument. These two iterators do not have the same type,
|
||||||
// so to keep the code paths uniform we accept an allocation
|
// so to keep the code paths uniform we accept an allocation
|
||||||
// (for RustCall ABI only).
|
// (for RustCall ABI only).
|
||||||
let caller_args: Cow<'_, [OpTy<'tcx, M::Provenance>]> =
|
let caller_args: Cow<'_, [FnArg<'tcx, M::Provenance>]> =
|
||||||
if caller_abi == Abi::RustCall && !args.is_empty() {
|
if caller_abi == Abi::RustCall && !args.is_empty() {
|
||||||
// Untuple
|
// Untuple
|
||||||
let (untuple_arg, args) = args.split_last().unwrap();
|
let (untuple_arg, args) = args.split_last().unwrap();
|
||||||
|
@ -458,11 +547,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(|a| Ok(a.clone()))
|
.map(|a| Ok(a.clone()))
|
||||||
.chain(
|
.chain(
|
||||||
(0..untuple_arg.layout.fields.count())
|
(0..untuple_arg.layout().fields.count())
|
||||||
.map(|i| self.operand_field(untuple_arg, i)),
|
.map(|i| self.fn_arg_field(untuple_arg, i)),
|
||||||
)
|
)
|
||||||
.collect::<InterpResult<'_, Vec<OpTy<'tcx, M::Provenance>>>>(
|
.collect::<InterpResult<'_, Vec<_>>>()?,
|
||||||
)?,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Plain arg passing
|
// Plain arg passing
|
||||||
|
@ -523,6 +611,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
caller_ty = caller_ty,
|
caller_ty = caller_ty,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Ensure the return place is aligned and dereferenceable, and protect it for
|
||||||
|
// in-place return value passing.
|
||||||
|
if let Either::Left(mplace) = destination.as_mplace_or_local() {
|
||||||
|
self.check_mplace(mplace)?;
|
||||||
|
} else {
|
||||||
|
// Nothing to do for locals, they are always properly allocated and aligned.
|
||||||
|
}
|
||||||
|
M::protect_in_place_function_argument(self, destination)?;
|
||||||
};
|
};
|
||||||
match res {
|
match res {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -538,7 +634,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// We have to implement all "object safe receivers". So we have to go search for a
|
// We have to implement all "object safe receivers". So we have to go search for a
|
||||||
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
|
// pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively
|
||||||
// unwrap those newtypes until we are there.
|
// unwrap those newtypes until we are there.
|
||||||
let mut receiver = args[0].clone();
|
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
|
||||||
|
// really pass the argument in-place anyway, and we are constructing a new
|
||||||
|
// `Immediate` receiver.
|
||||||
|
let mut receiver = self.copy_fn_arg(&args[0])?;
|
||||||
let receiver_place = loop {
|
let receiver_place = loop {
|
||||||
match receiver.layout.ty.kind() {
|
match receiver.layout.ty.kind() {
|
||||||
ty::Ref(..) | ty::RawPtr(..) => {
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
|
@ -648,11 +747,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjust receiver argument. Layout can be any (thin) ptr.
|
// Adjust receiver argument. Layout can be any (thin) ptr.
|
||||||
args[0] = ImmTy::from_immediate(
|
args[0] = FnArg::Copy(
|
||||||
Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
|
ImmTy::from_immediate(
|
||||||
self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?,
|
Scalar::from_maybe_pointer(adjusted_receiver, self).into(),
|
||||||
)
|
self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, dyn_ty))?,
|
||||||
.into();
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
trace!("Patched receiver operand to {:#?}", args[0]);
|
trace!("Patched receiver operand to {:#?}", args[0]);
|
||||||
// recurse with concrete function
|
// recurse with concrete function
|
||||||
self.eval_fn_call(
|
self.eval_fn_call(
|
||||||
|
@ -710,7 +811,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
self.eval_fn_call(
|
self.eval_fn_call(
|
||||||
FnVal::Instance(instance),
|
FnVal::Instance(instance),
|
||||||
(Abi::Rust, fn_abi),
|
(Abi::Rust, fn_abi),
|
||||||
&[arg.into()],
|
&[FnArg::Copy(arg.into())],
|
||||||
false,
|
false,
|
||||||
&ret.into(),
|
&ret.into(),
|
||||||
Some(target),
|
Some(target),
|
||||||
|
|
|
@ -13,7 +13,7 @@ use super::{InterpCx, MPlaceTy, Machine, OpTy, PlaceTy};
|
||||||
/// A thing that we can project into, and that has a layout.
|
/// A thing that we can project into, and that has a layout.
|
||||||
/// This wouldn't have to depend on `Machine` but with the current type inference,
|
/// This wouldn't have to depend on `Machine` but with the current type inference,
|
||||||
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
|
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
|
||||||
pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
|
pub trait Value<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||||
/// Gets this value's layout.
|
/// Gets this value's layout.
|
||||||
fn layout(&self) -> TyAndLayout<'tcx>;
|
fn layout(&self) -> TyAndLayout<'tcx>;
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
|
||||||
/// A thing that we can project into given *mutable* access to `ecx`, and that has a layout.
|
/// A thing that we can project into given *mutable* access to `ecx`, and that has a layout.
|
||||||
/// This wouldn't have to depend on `Machine` but with the current type inference,
|
/// This wouldn't have to depend on `Machine` but with the current type inference,
|
||||||
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
|
/// that's just more convenient to work with (avoids repeating all the `Machine` bounds).
|
||||||
pub trait ValueMut<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Sized {
|
pub trait ValueMut<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
|
||||||
/// Gets this value's layout.
|
/// Gets this value's layout.
|
||||||
fn layout(&self) -> TyAndLayout<'tcx>;
|
fn layout(&self) -> TyAndLayout<'tcx>;
|
||||||
|
|
||||||
|
|
|
@ -1453,13 +1453,13 @@ mod signal_handler {
|
||||||
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
|
||||||
/// process, print a stack trace and then exit.
|
/// process, print a stack trace and then exit.
|
||||||
pub(super) fn install() {
|
pub(super) fn install() {
|
||||||
|
use std::alloc::{alloc, Layout};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
const ALT_STACK_SIZE: usize = libc::MINSIGSTKSZ + 64 * 1024;
|
let alt_stack_size: usize = min_sigstack_size() + 64 * 1024;
|
||||||
let mut alt_stack: libc::stack_t = std::mem::zeroed();
|
let mut alt_stack: libc::stack_t = std::mem::zeroed();
|
||||||
alt_stack.ss_sp =
|
alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast();
|
||||||
std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap())
|
alt_stack.ss_size = alt_stack_size;
|
||||||
as *mut libc::c_void;
|
|
||||||
alt_stack.ss_size = ALT_STACK_SIZE;
|
|
||||||
libc::sigaltstack(&alt_stack, std::ptr::null_mut());
|
libc::sigaltstack(&alt_stack, std::ptr::null_mut());
|
||||||
|
|
||||||
let mut sa: libc::sigaction = std::mem::zeroed();
|
let mut sa: libc::sigaction = std::mem::zeroed();
|
||||||
|
@ -1469,6 +1469,23 @@ mod signal_handler {
|
||||||
libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
|
libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Modern kernels on modern hardware can have dynamic signal stack sizes.
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
fn min_sigstack_size() -> usize {
|
||||||
|
const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51;
|
||||||
|
let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) };
|
||||||
|
// If getauxval couldn't find the entry, it returns 0,
|
||||||
|
// so take the higher of the "constant" and auxval.
|
||||||
|
// This transparently supports older kernels which don't provide AT_MINSIGSTKSZ
|
||||||
|
libc::MINSIGSTKSZ.max(dynamic_sigstksz as _)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not all OS support hardware where this is needed.
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||||
|
fn min_sigstack_size() -> usize {
|
||||||
|
libc::MINSIGSTKSZ
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
|
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
|
||||||
|
|
|
@ -109,8 +109,6 @@ pub enum DefKind {
|
||||||
InlineConst,
|
InlineConst,
|
||||||
/// Opaque type, aka `impl Trait`.
|
/// Opaque type, aka `impl Trait`.
|
||||||
OpaqueTy,
|
OpaqueTy,
|
||||||
/// A return-position `impl Trait` in a trait definition
|
|
||||||
ImplTraitPlaceholder,
|
|
||||||
Field,
|
Field,
|
||||||
/// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }`
|
/// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }`
|
||||||
LifetimeParam,
|
LifetimeParam,
|
||||||
|
@ -143,7 +141,6 @@ impl DefKind {
|
||||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
|
DefKind::Ctor(CtorOf::Struct, CtorKind::Fn) => "tuple struct",
|
||||||
DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
|
DefKind::Ctor(CtorOf::Struct, CtorKind::Const) => "unit struct",
|
||||||
DefKind::OpaqueTy => "opaque type",
|
DefKind::OpaqueTy => "opaque type",
|
||||||
DefKind::ImplTraitPlaceholder => "opaque type in trait",
|
|
||||||
DefKind::TyAlias => "type alias",
|
DefKind::TyAlias => "type alias",
|
||||||
DefKind::TraitAlias => "trait alias",
|
DefKind::TraitAlias => "trait alias",
|
||||||
DefKind::AssocTy => "associated type",
|
DefKind::AssocTy => "associated type",
|
||||||
|
@ -227,8 +224,7 @@ impl DefKind {
|
||||||
| DefKind::Use
|
| DefKind::Use
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. } => None,
|
||||||
| DefKind::ImplTraitPlaceholder => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +258,6 @@ impl DefKind {
|
||||||
| DefKind::Use
|
| DefKind::Use
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::TyParam
|
| DefKind::TyParam
|
||||||
|
|
|
@ -36,7 +36,6 @@ pub enum Target {
|
||||||
GlobalAsm,
|
GlobalAsm,
|
||||||
TyAlias,
|
TyAlias,
|
||||||
OpaqueTy,
|
OpaqueTy,
|
||||||
ImplTraitPlaceholder,
|
|
||||||
Enum,
|
Enum,
|
||||||
Variant,
|
Variant,
|
||||||
Struct,
|
Struct,
|
||||||
|
@ -80,13 +79,7 @@ impl Target {
|
||||||
ItemKind::ForeignMod { .. } => Target::ForeignMod,
|
ItemKind::ForeignMod { .. } => Target::ForeignMod,
|
||||||
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
|
||||||
ItemKind::TyAlias(..) => Target::TyAlias,
|
ItemKind::TyAlias(..) => Target::TyAlias,
|
||||||
ItemKind::OpaqueTy(ref opaque) => {
|
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
|
||||||
if opaque.in_trait {
|
|
||||||
Target::ImplTraitPlaceholder
|
|
||||||
} else {
|
|
||||||
Target::OpaqueTy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemKind::Enum(..) => Target::Enum,
|
ItemKind::Enum(..) => Target::Enum,
|
||||||
ItemKind::Struct(..) => Target::Struct,
|
ItemKind::Struct(..) => Target::Struct,
|
||||||
ItemKind::Union(..) => Target::Union,
|
ItemKind::Union(..) => Target::Union,
|
||||||
|
@ -110,7 +103,6 @@ impl Target {
|
||||||
DefKind::GlobalAsm => Target::GlobalAsm,
|
DefKind::GlobalAsm => Target::GlobalAsm,
|
||||||
DefKind::TyAlias => Target::TyAlias,
|
DefKind::TyAlias => Target::TyAlias,
|
||||||
DefKind::OpaqueTy => Target::OpaqueTy,
|
DefKind::OpaqueTy => Target::OpaqueTy,
|
||||||
DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder,
|
|
||||||
DefKind::Enum => Target::Enum,
|
DefKind::Enum => Target::Enum,
|
||||||
DefKind::Struct => Target::Struct,
|
DefKind::Struct => Target::Struct,
|
||||||
DefKind::Union => Target::Union,
|
DefKind::Union => Target::Union,
|
||||||
|
@ -165,7 +157,6 @@ impl Target {
|
||||||
Target::GlobalAsm => "global asm",
|
Target::GlobalAsm => "global asm",
|
||||||
Target::TyAlias => "type alias",
|
Target::TyAlias => "type alias",
|
||||||
Target::OpaqueTy => "opaque type",
|
Target::OpaqueTy => "opaque type",
|
||||||
Target::ImplTraitPlaceholder => "opaque type in trait",
|
|
||||||
Target::Enum => "enum",
|
Target::Enum => "enum",
|
||||||
Target::Variant => "enum variant",
|
Target::Variant => "enum variant",
|
||||||
Target::Struct => "struct",
|
Target::Struct => "struct",
|
||||||
|
|
|
@ -2128,7 +2128,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
|
|
||||||
let span = path.span;
|
let span = path.span;
|
||||||
match path.res {
|
match path.res {
|
||||||
Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
|
Res::Def(DefKind::OpaqueTy, did) => {
|
||||||
// Check for desugared `impl Trait`.
|
// Check for desugared `impl Trait`.
|
||||||
assert!(tcx.is_type_alias_impl_trait(did));
|
assert!(tcx.is_type_alias_impl_trait(did));
|
||||||
let item_segment = path.segments.split_last().unwrap();
|
let item_segment = path.segments.split_last().unwrap();
|
||||||
|
@ -2439,7 +2439,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
|
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
|
||||||
// generate the def_id of an associated type for the trait and return as
|
// generate the def_id of an associated type for the trait and return as
|
||||||
// type a projection.
|
// type a projection.
|
||||||
let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
let def_id = if in_trait {
|
||||||
tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
|
tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
|
||||||
} else {
|
} else {
|
||||||
local_def_id.to_def_id()
|
local_def_id.to_def_id()
|
||||||
|
|
|
@ -302,16 +302,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||||
|
|
||||||
if let ItemKind::OpaqueTy(&hir::OpaqueTy {
|
if let ItemKind::OpaqueTy(&hir::OpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
|
||||||
in_trait,
|
|
||||||
..
|
..
|
||||||
}) = item.kind
|
}) = item.kind
|
||||||
{
|
{
|
||||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||||
let opaque_identity_ty = if in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
let opaque_identity_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs);
|
||||||
Ty::new_projection(tcx, def_id.to_def_id(), substs)
|
|
||||||
} else {
|
|
||||||
Ty::new_opaque(tcx, def_id.to_def_id(), substs)
|
|
||||||
};
|
|
||||||
let mut visitor = ProhibitOpaqueVisitor {
|
let mut visitor = ProhibitOpaqueVisitor {
|
||||||
opaque_identity_ty,
|
opaque_identity_ty,
|
||||||
parent_count: tcx.generics_of(def_id).parent_count as u32,
|
parent_count: tcx.generics_of(def_id).parent_count as u32,
|
||||||
|
@ -576,17 +571,6 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
|
||||||
check_opaque(tcx, id);
|
check_opaque(tcx, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefKind::ImplTraitPlaceholder => {
|
|
||||||
let parent = tcx.impl_trait_in_trait_parent_fn(id.owner_id.to_def_id());
|
|
||||||
// Only check the validity of this opaque type if the function has a default body
|
|
||||||
if let hir::Node::TraitItem(hir::TraitItem {
|
|
||||||
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
|
|
||||||
..
|
|
||||||
}) = tcx.hir().get_by_def_id(parent.expect_local())
|
|
||||||
{
|
|
||||||
check_opaque(tcx, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DefKind::TyAlias => {
|
DefKind::TyAlias => {
|
||||||
let pty_ty = tcx.type_of(id.owner_id).subst_identity();
|
let pty_ty = tcx.type_of(id.owner_id).subst_identity();
|
||||||
let generics = tcx.generics_of(id.owner_id);
|
let generics = tcx.generics_of(id.owner_id);
|
||||||
|
|
|
@ -113,16 +113,12 @@ pub(super) fn explicit_item_bounds(
|
||||||
..
|
..
|
||||||
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
}) => associated_type_bounds(tcx, def_id, bounds, *span),
|
||||||
hir::Node::Item(hir::Item {
|
hir::Node::Item(hir::Item {
|
||||||
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }),
|
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
|
||||||
span,
|
span,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
let substs = InternalSubsts::identity_for_item(tcx, def_id);
|
||||||
let item_ty = if *in_trait && !tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), substs);
|
||||||
Ty::new_projection(tcx, def_id.to_def_id(), substs)
|
|
||||||
} else {
|
|
||||||
Ty::new_opaque(tcx, def_id.to_def_id(), substs)
|
|
||||||
};
|
|
||||||
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
|
||||||
}
|
}
|
||||||
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
|
hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[],
|
||||||
|
|
|
@ -109,20 +109,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Fn => {
|
ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
|
||||||
if !tcx.lower_impl_trait_in_trait_to_assoc_ty()
|
|
||||||
&& item.defaultness(tcx).has_value()
|
|
||||||
&& tcx.impl_method_has_trait_impl_trait_tys(item.def_id)
|
|
||||||
&& let Ok(table) = tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
|
|
||||||
{
|
|
||||||
table.values().copied().flat_map(|ty| {
|
|
||||||
cgp::parameters_for(&ty.subst_identity(), true)
|
|
||||||
}).collect()
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::AssocKind::Const => vec![],
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
|
||||||
let crate_map = tcx.crate_variances(());
|
let crate_map = tcx.crate_variances(());
|
||||||
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
|
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
|
||||||
}
|
}
|
||||||
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
|
DefKind::OpaqueTy => {
|
||||||
return variance_of_opaque(tcx, item_def_id);
|
return variance_of_opaque(tcx, item_def_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -115,14 +115,6 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
|
||||||
{
|
{
|
||||||
self.visit_opaque(*def_id, substs)
|
self.visit_opaque(*def_id, substs)
|
||||||
}
|
}
|
||||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) check whether this is necessary
|
|
||||||
// at all for RPITITs.
|
|
||||||
ty::Alias(_, ty::AliasTy { def_id, substs, .. })
|
|
||||||
if self.tcx.is_impl_trait_in_trait(*def_id)
|
|
||||||
&& !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() =>
|
|
||||||
{
|
|
||||||
self.visit_opaque(*def_id, substs)
|
|
||||||
}
|
|
||||||
_ => t.super_visit_with(self),
|
_ => t.super_visit_with(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
|
fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
|
||||||
&*tcx.typeck(def_id).used_trait_imports
|
&tcx.typeck(def_id).used_trait_imports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub use self::MethodError::*;
|
||||||
|
|
||||||
use crate::errors::OpMethodGenericParams;
|
use crate::errors::OpMethodGenericParams;
|
||||||
use crate::FnCtxt;
|
use crate::FnCtxt;
|
||||||
use rustc_data_structures::sync::Lrc;
|
|
||||||
use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage};
|
use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||||
|
@ -190,11 +189,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
|
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
|
||||||
|
|
||||||
for import_id in &pick.import_ids {
|
for &import_id in &pick.import_ids {
|
||||||
debug!("used_trait_import: {:?}", import_id);
|
debug!("used_trait_import: {:?}", import_id);
|
||||||
Lrc::get_mut(&mut self.typeck_results.borrow_mut().used_trait_imports)
|
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
|
||||||
.unwrap()
|
|
||||||
.insert(*import_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None);
|
self.tcx.check_stability(pick.item.def_id, Some(call_expr.hir_id), span, None);
|
||||||
|
@ -567,10 +564,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
debug!(?pick);
|
debug!(?pick);
|
||||||
{
|
{
|
||||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||||
let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap();
|
|
||||||
for import_id in pick.import_ids {
|
for import_id in pick.import_ids {
|
||||||
debug!(used_trait_import=?import_id);
|
debug!(used_trait_import=?import_id);
|
||||||
used_trait_imports.insert(import_id);
|
typeck_results.used_trait_imports.insert(import_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,8 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
mut def_bm: BindingMode,
|
mut def_bm: BindingMode,
|
||||||
) -> (Ty<'tcx>, BindingMode) {
|
) -> (Ty<'tcx>, BindingMode) {
|
||||||
let mut expected = self.resolve_vars_with_obligations(expected);
|
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||||
|
|
||||||
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
||||||
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
||||||
// the `Some(5)` which is not of type Ref.
|
// the `Some(5)` which is not of type Ref.
|
||||||
|
@ -353,7 +352,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// Preserve the reference type. We'll need it later during THIR lowering.
|
// Preserve the reference type. We'll need it later during THIR lowering.
|
||||||
pat_adjustments.push(expected);
|
pat_adjustments.push(expected);
|
||||||
|
|
||||||
expected = inner_ty;
|
expected = self.try_structurally_resolve_type(pat.span, inner_ty);
|
||||||
def_bm = ty::BindByReference(match def_bm {
|
def_bm = ty::BindByReference(match def_bm {
|
||||||
// If default binding mode is by value, make it `ref` or `ref mut`
|
// If default binding mode is by value, make it `ref` or `ref mut`
|
||||||
// (depending on whether we observe `&` or `&mut`).
|
// (depending on whether we observe `&` or `&mut`).
|
||||||
|
@ -627,6 +626,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
local_ty
|
local_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When a variable is bound several times in a `PatKind::Or`, it'll resolve all of the
|
||||||
|
/// subsequent bindings of the same name to the first usage. Verify that all of these
|
||||||
|
/// bindings have the same type by comparing them all against the type of that first pat.
|
||||||
fn check_binding_alt_eq_ty(
|
fn check_binding_alt_eq_ty(
|
||||||
&self,
|
&self,
|
||||||
ba: hir::BindingAnnotation,
|
ba: hir::BindingAnnotation,
|
||||||
|
@ -638,7 +640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let var_ty = self.local_ty(span, var_id);
|
let var_ty = self.local_ty(span, var_id);
|
||||||
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
|
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
let var_ty = self.resolve_vars_with_obligations(var_ty);
|
let var_ty = self.resolve_vars_if_possible(var_ty);
|
||||||
let msg = format!("first introduced with type `{var_ty}` here");
|
let msg = format!("first introduced with type `{var_ty}` here");
|
||||||
err.span_label(hir.span(var_id), msg);
|
err.span_label(hir.span(var_id), msg);
|
||||||
let in_match = hir.parent_iter(var_id).any(|(_, n)| {
|
let in_match = hir.parent_iter(var_id).any(|(_, n)| {
|
||||||
|
@ -656,7 +658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&mut err,
|
&mut err,
|
||||||
span,
|
span,
|
||||||
var_ty,
|
var_ty,
|
||||||
self.resolve_vars_with_obligations(ty),
|
self.resolve_vars_if_possible(ty),
|
||||||
ba,
|
ba,
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
|
|
@ -162,10 +162,18 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
|
||||||
let mut infcx_inner = infcx.inner.borrow_mut();
|
let mut infcx_inner = infcx.inner.borrow_mut();
|
||||||
let ty_vars = infcx_inner.type_variables();
|
let ty_vars = infcx_inner.type_variables();
|
||||||
let var_origin = ty_vars.var_origin(ty_vid);
|
let var_origin = ty_vars.var_origin(ty_vid);
|
||||||
if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind
|
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind
|
||||||
&& !var_origin.span.from_expansion()
|
&& !var_origin.span.from_expansion()
|
||||||
{
|
{
|
||||||
Some(name)
|
let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id));
|
||||||
|
let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap();
|
||||||
|
let generic_param_def = generics.param_at(idx as usize, infcx.tcx);
|
||||||
|
if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind
|
||||||
|
{
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(name)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,52 +464,53 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> Option<TypeErrorAdditionalDiags> {
|
) -> Option<TypeErrorAdditionalDiags> {
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
if let Some(node) = self.tcx.hir().find_by_def_id(cause.body_id) &&
|
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) {
|
||||||
let hir::Node::Item(hir::Item {
|
let body = hir.body(body_id);
|
||||||
kind: hir::ItemKind::Fn(_sig, _, body_id), ..
|
|
||||||
}) = node {
|
|
||||||
let body = hir.body(*body_id);
|
|
||||||
|
|
||||||
/// Find the if expression with given span
|
/// Find the if expression with given span
|
||||||
struct IfVisitor {
|
struct IfVisitor {
|
||||||
pub result: bool,
|
pub result: bool,
|
||||||
pub found_if: bool,
|
pub found_if: bool,
|
||||||
pub err_span: Span,
|
pub err_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for IfVisitor {
|
impl<'v> Visitor<'v> for IfVisitor {
|
||||||
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
||||||
if self.result { return; }
|
if self.result {
|
||||||
match ex.kind {
|
return;
|
||||||
hir::ExprKind::If(cond, _, _) => {
|
|
||||||
self.found_if = true;
|
|
||||||
walk_expr(self, cond);
|
|
||||||
self.found_if = false;
|
|
||||||
}
|
}
|
||||||
_ => walk_expr(self, ex),
|
match ex.kind {
|
||||||
|
hir::ExprKind::If(cond, _, _) => {
|
||||||
|
self.found_if = true;
|
||||||
|
walk_expr(self, cond);
|
||||||
|
self.found_if = false;
|
||||||
|
}
|
||||||
|
_ => walk_expr(self, ex),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
||||||
|
if let hir::StmtKind::Local(hir::Local {
|
||||||
|
span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
|
||||||
|
}) = &ex.kind
|
||||||
|
&& self.found_if
|
||||||
|
&& span.eq(&self.err_span) {
|
||||||
|
self.result = true;
|
||||||
|
}
|
||||||
|
walk_stmt(self, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
||||||
|
hir::intravisit::walk_body(self, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) {
|
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
|
||||||
if let hir::StmtKind::Local(hir::Local {
|
visitor.visit_body(&body);
|
||||||
span, pat: hir::Pat{..}, ty: None, init: Some(_), ..
|
if visitor.result {
|
||||||
}) = &ex.kind
|
return Some(TypeErrorAdditionalDiags::AddLetForLetChains {
|
||||||
&& self.found_if
|
span: span.shrink_to_lo(),
|
||||||
&& span.eq(&self.err_span) {
|
});
|
||||||
self.result = true;
|
|
||||||
}
|
|
||||||
walk_stmt(self, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
|
|
||||||
hir::intravisit::walk_body(self, body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false };
|
|
||||||
visitor.visit_body(&body);
|
|
||||||
if visitor.result {
|
|
||||||
return Some(TypeErrorAdditionalDiags::AddLetForLetChains{span: span.shrink_to_lo()});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -332,6 +332,39 @@ pub struct InferCtxt<'tcx> {
|
||||||
next_trait_solver: bool,
|
next_trait_solver: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
|
||||||
|
fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
|
||||||
|
use InferTy::*;
|
||||||
|
match ty {
|
||||||
|
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||||
|
// ty infers will give you the universe of the var it resolved to not the universe
|
||||||
|
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||||
|
// try to print out `?0.1` it will just print `?0`.
|
||||||
|
TyVar(ty_vid) => match self.probe_ty_var(ty_vid) {
|
||||||
|
Err(universe) => Some(universe),
|
||||||
|
Ok(_) => None,
|
||||||
|
},
|
||||||
|
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> {
|
||||||
|
use ty::InferConst::*;
|
||||||
|
match ct {
|
||||||
|
// Same issue as with `universe_of_ty`
|
||||||
|
Var(ct_vid) => match self.probe_const_var(ct_vid) {
|
||||||
|
Err(universe) => Some(universe),
|
||||||
|
Ok(_) => None,
|
||||||
|
},
|
||||||
|
Fresh(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||||
|
Some(self.universe_of_region_vid(lt))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// See the `error_reporting` module for more details.
|
/// See the `error_reporting` module for more details.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
|
||||||
pub enum ValuePairs<'tcx> {
|
pub enum ValuePairs<'tcx> {
|
||||||
|
@ -1068,6 +1101,11 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
|
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the universe that the region variable `r` was created in.
|
||||||
|
pub fn universe_of_region_vid(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
|
||||||
|
self.inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
|
||||||
|
}
|
||||||
|
|
||||||
/// Number of region variables created so far.
|
/// Number of region variables created so far.
|
||||||
pub fn num_region_vars(&self) -> usize {
|
pub fn num_region_vars(&self) -> usize {
|
||||||
self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()
|
self.inner.borrow_mut().unwrap_region_constraints().num_region_vars()
|
||||||
|
|
|
@ -215,6 +215,9 @@ lint_expectation = this lint expectation is unfulfilled
|
||||||
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
||||||
.rationale = {$rationale}
|
.rationale = {$rationale}
|
||||||
|
|
||||||
|
lint_fn_null_check = function pointers are not nullable, so checking them for null will always return false
|
||||||
|
.help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
|
||||||
|
|
||||||
lint_for_loops_over_fallibles =
|
lint_for_loops_over_fallibles =
|
||||||
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
||||||
.suggestion = consider using `if let` to clear intent
|
.suggestion = consider using `if let` to clear intent
|
||||||
|
|
112
compiler/rustc_lint/src/fn_null_check.rs
Normal file
112
compiler/rustc_lint/src/fn_null_check.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
use crate::{lints::FnNullCheckDiag, LateContext, LateLintPass, LintContext};
|
||||||
|
use rustc_ast::LitKind;
|
||||||
|
use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
|
||||||
|
use rustc_session::{declare_lint, declare_lint_pass};
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `incorrect_fn_null_checks` lint checks for expression that checks if a
|
||||||
|
/// function pointer is null.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # fn test() {}
|
||||||
|
/// let fn_ptr: fn() = /* somehow obtained nullable function pointer */
|
||||||
|
/// # test;
|
||||||
|
///
|
||||||
|
/// if (fn_ptr as *const ()).is_null() { /* ... */ }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Function pointers are assumed to be non-null, checking them for null will always
|
||||||
|
/// return false.
|
||||||
|
INCORRECT_FN_NULL_CHECKS,
|
||||||
|
Warn,
|
||||||
|
"incorrect checking of null function pointer"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(IncorrectFnNullChecks => [INCORRECT_FN_NULL_CHECKS]);
|
||||||
|
|
||||||
|
fn is_fn_ptr_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||||
|
let mut expr = expr.peel_blocks();
|
||||||
|
let mut had_at_least_one_cast = false;
|
||||||
|
while let ExprKind::Cast(cast_expr, cast_ty) = expr.kind
|
||||||
|
&& let TyKind::Ptr(_) = cast_ty.kind {
|
||||||
|
expr = cast_expr.peel_blocks();
|
||||||
|
had_at_least_one_cast = true;
|
||||||
|
}
|
||||||
|
had_at_least_one_cast && cx.typeck_results().expr_ty_adjusted(expr).is_fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for IncorrectFnNullChecks {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
match expr.kind {
|
||||||
|
// Catching:
|
||||||
|
// <*<const/mut> <ty>>::is_null(fn_ptr as *<const/mut> <ty>)
|
||||||
|
ExprKind::Call(path, [arg])
|
||||||
|
if let ExprKind::Path(ref qpath) = path.kind
|
||||||
|
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||||
|
&& matches!(
|
||||||
|
cx.tcx.get_diagnostic_name(def_id),
|
||||||
|
Some(sym::ptr_const_is_null | sym::ptr_is_null)
|
||||||
|
)
|
||||||
|
&& is_fn_ptr_cast(cx, arg) =>
|
||||||
|
{
|
||||||
|
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catching:
|
||||||
|
// (fn_ptr as *<const/mut> <ty>).is_null()
|
||||||
|
ExprKind::MethodCall(_, receiver, _, _)
|
||||||
|
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||||
|
&& matches!(
|
||||||
|
cx.tcx.get_diagnostic_name(def_id),
|
||||||
|
Some(sym::ptr_const_is_null | sym::ptr_is_null)
|
||||||
|
)
|
||||||
|
&& is_fn_ptr_cast(cx, receiver) =>
|
||||||
|
{
|
||||||
|
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprKind::Binary(op, left, right) if matches!(op.node, BinOpKind::Eq) => {
|
||||||
|
let to_check: &Expr<'_>;
|
||||||
|
if is_fn_ptr_cast(cx, left) {
|
||||||
|
to_check = right;
|
||||||
|
} else if is_fn_ptr_cast(cx, right) {
|
||||||
|
to_check = left;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match to_check.kind {
|
||||||
|
// Catching:
|
||||||
|
// (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
|
||||||
|
ExprKind::Cast(cast_expr, _)
|
||||||
|
if let ExprKind::Lit(spanned) = cast_expr.kind
|
||||||
|
&& let LitKind::Int(v, _) = spanned.node && v == 0 =>
|
||||||
|
{
|
||||||
|
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Catching:
|
||||||
|
// (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
|
||||||
|
ExprKind::Call(path, [])
|
||||||
|
if let ExprKind::Path(ref qpath) = path.kind
|
||||||
|
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||||
|
&& let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
|
||||||
|
&& (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
|
||||||
|
{
|
||||||
|
cx.emit_spanned_lint(INCORRECT_FN_NULL_CHECKS, expr.span, FnNullCheckDiag)
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,6 +58,7 @@ mod early;
|
||||||
mod enum_intrinsics_non_enums;
|
mod enum_intrinsics_non_enums;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod expect;
|
mod expect;
|
||||||
|
mod fn_null_check;
|
||||||
mod for_loops_over_fallibles;
|
mod for_loops_over_fallibles;
|
||||||
pub mod hidden_unicode_codepoints;
|
pub mod hidden_unicode_codepoints;
|
||||||
mod internal;
|
mod internal;
|
||||||
|
@ -102,6 +103,7 @@ use cast_ref_to_mut::*;
|
||||||
use deref_into_dyn_supertrait::*;
|
use deref_into_dyn_supertrait::*;
|
||||||
use drop_forget_useless::*;
|
use drop_forget_useless::*;
|
||||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||||
|
use fn_null_check::*;
|
||||||
use for_loops_over_fallibles::*;
|
use for_loops_over_fallibles::*;
|
||||||
use hidden_unicode_codepoints::*;
|
use hidden_unicode_codepoints::*;
|
||||||
use internal::*;
|
use internal::*;
|
||||||
|
@ -225,6 +227,7 @@ late_lint_methods!(
|
||||||
// Depends on types used in type definitions
|
// Depends on types used in type definitions
|
||||||
MissingCopyImplementations: MissingCopyImplementations,
|
MissingCopyImplementations: MissingCopyImplementations,
|
||||||
// Depends on referenced function signatures in expressions
|
// Depends on referenced function signatures in expressions
|
||||||
|
IncorrectFnNullChecks: IncorrectFnNullChecks,
|
||||||
MutableTransmutes: MutableTransmutes,
|
MutableTransmutes: MutableTransmutes,
|
||||||
TypeAliasBounds: TypeAliasBounds,
|
TypeAliasBounds: TypeAliasBounds,
|
||||||
TrivialConstraints: TrivialConstraints,
|
TrivialConstraints: TrivialConstraints,
|
||||||
|
|
|
@ -613,6 +613,12 @@ pub struct ExpectationNote {
|
||||||
pub rationale: Symbol,
|
pub rationale: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn_null_check.rs
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_fn_null_check)]
|
||||||
|
#[help]
|
||||||
|
pub struct FnNullCheckDiag;
|
||||||
|
|
||||||
// for_loops_over_fallibles.rs
|
// for_loops_over_fallibles.rs
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_for_loops_over_fallibles)]
|
#[diag(lint_for_loops_over_fallibles)]
|
||||||
|
|
|
@ -4084,7 +4084,7 @@ declare_lint! {
|
||||||
///
|
///
|
||||||
/// ### Explanation
|
/// ### Explanation
|
||||||
///
|
///
|
||||||
/// The preferred location for where clauses on associated types in impls
|
/// The preferred location for where clauses on associated types
|
||||||
/// is after the type. However, for most of generic associated types development,
|
/// is after the type. However, for most of generic associated types development,
|
||||||
/// it was only accepted before the equals. To provide a transition period and
|
/// it was only accepted before the equals. To provide a transition period and
|
||||||
/// further evaluate this change, both are currently accepted. At some point in
|
/// further evaluate this change, both are currently accepted. At some point in
|
||||||
|
|
|
@ -1616,17 +1616,6 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
|
||||||
LLVMSetLinkage(V, fromRust(RustLinkage));
|
LLVMSetLinkage(V, fromRust(RustLinkage));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: replace with LLVMConstInBoundsGEP2 when bumped minimal version to llvm-14
|
|
||||||
extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty,
|
|
||||||
LLVMValueRef ConstantVal,
|
|
||||||
LLVMValueRef *ConstantIndices,
|
|
||||||
unsigned NumIndices) {
|
|
||||||
ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
|
|
||||||
NumIndices);
|
|
||||||
Constant *Val = unwrap<Constant>(ConstantVal);
|
|
||||||
return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
|
extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
|
||||||
auto C = unwrap<llvm::ConstantInt>(CV);
|
auto C = unwrap<llvm::ConstantInt>(CV);
|
||||||
if (C->getBitWidth() > 64)
|
if (C->getBitWidth() > 64)
|
||||||
|
|
|
@ -824,7 +824,6 @@ fn should_encode_span(def_kind: DefKind) -> bool {
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::Closure
|
| DefKind::Closure
|
||||||
|
@ -867,7 +866,6 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::LifetimeParam
|
| DefKind::LifetimeParam
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
| DefKind::Generator => false,
|
| DefKind::Generator => false,
|
||||||
|
@ -902,7 +900,6 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool {
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::LifetimeParam
|
| DefKind::LifetimeParam
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
|
@ -939,7 +936,6 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::Closure
|
| DefKind::Closure
|
||||||
|
@ -966,7 +962,6 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Enum
|
| DefKind::Enum
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
|
@ -1033,7 +1028,6 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
|
||||||
| DefKind::Enum
|
| DefKind::Enum
|
||||||
| DefKind::Variant
|
| DefKind::Variant
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Fn
|
| DefKind::Fn
|
||||||
| DefKind::Ctor(..)
|
| DefKind::Ctor(..)
|
||||||
| DefKind::AssocFn => true,
|
| DefKind::AssocFn => true,
|
||||||
|
@ -1083,7 +1077,6 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::TyParam
|
| DefKind::TyParam
|
||||||
|
@ -1134,19 +1127,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DefKind::ImplTraitPlaceholder => {
|
|
||||||
let parent_def_id = tcx.impl_trait_in_trait_parent_fn(def_id.to_def_id());
|
|
||||||
let assoc_item = tcx.associated_item(parent_def_id);
|
|
||||||
match assoc_item.container {
|
|
||||||
// Always encode an RPIT in an impl fn, since it always has a body
|
|
||||||
ty::AssocItemContainer::ImplContainer => true,
|
|
||||||
ty::AssocItemContainer::TraitContainer => {
|
|
||||||
// Encode an RPIT for a trait only if the trait has a default body
|
|
||||||
assoc_item.defaultness(tcx).has_value()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DefKind::AssocTy => {
|
DefKind::AssocTy => {
|
||||||
let assoc_item = tcx.associated_item(def_id);
|
let assoc_item = tcx.associated_item(def_id);
|
||||||
match assoc_item.container {
|
match assoc_item.container {
|
||||||
|
@ -1192,7 +1172,6 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
|
||||||
| DefKind::Ctor(..)
|
| DefKind::Ctor(..)
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::AssocConst
|
| DefKind::AssocConst
|
||||||
|
@ -1235,7 +1214,6 @@ fn should_encode_constness(def_kind: DefKind) -> bool {
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::Impl { of_trait: false }
|
| DefKind::Impl { of_trait: false }
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::Generator
|
| DefKind::Generator
|
||||||
| DefKind::ConstParam
|
| DefKind::ConstParam
|
||||||
|
@ -1268,7 +1246,6 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
||||||
| DefKind::Static(..)
|
| DefKind::Static(..)
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::Impl { .. }
|
| DefKind::Impl { .. }
|
||||||
| DefKind::AssocFn
|
| DefKind::AssocFn
|
||||||
|
@ -1289,11 +1266,8 @@ fn should_encode_const(def_kind: DefKind) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only encode impl trait in trait when using `lower-impl-trait-in-trait-to-assoc-ty` unstable
|
|
||||||
// option.
|
|
||||||
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
|
||||||
if tcx.lower_impl_trait_in_trait_to_assoc_ty()
|
if let Some(assoc_item) = tcx.opt_associated_item(def_id)
|
||||||
&& let Some(assoc_item) = tcx.opt_associated_item(def_id)
|
|
||||||
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
|
&& assoc_item.container == ty::AssocItemContainer::TraitContainer
|
||||||
&& assoc_item.kind == ty::AssocKind::Fn
|
&& assoc_item.kind == ty::AssocKind::Fn
|
||||||
{
|
{
|
||||||
|
@ -1447,9 +1421,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||||
.is_type_alias_impl_trait
|
.is_type_alias_impl_trait
|
||||||
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
|
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
|
||||||
}
|
}
|
||||||
if let DefKind::ImplTraitPlaceholder = def_kind {
|
|
||||||
self.encode_explicit_item_bounds(def_id);
|
|
||||||
}
|
|
||||||
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
|
||||||
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
|
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -142,7 +142,6 @@ fixed_size_enum! {
|
||||||
( AnonConst )
|
( AnonConst )
|
||||||
( InlineConst )
|
( InlineConst )
|
||||||
( OpaqueTy )
|
( OpaqueTy )
|
||||||
( ImplTraitPlaceholder )
|
|
||||||
( Field )
|
( Field )
|
||||||
( LifetimeParam )
|
( LifetimeParam )
|
||||||
( GlobalAsm )
|
( GlobalAsm )
|
||||||
|
|
|
@ -195,13 +195,7 @@ impl<'hir> Map<'hir> {
|
||||||
ItemKind::Fn(..) => DefKind::Fn,
|
ItemKind::Fn(..) => DefKind::Fn,
|
||||||
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
|
ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
|
||||||
ItemKind::Mod(..) => DefKind::Mod,
|
ItemKind::Mod(..) => DefKind::Mod,
|
||||||
ItemKind::OpaqueTy(ref opaque) => {
|
ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
|
||||||
if opaque.in_trait && !self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
|
||||||
DefKind::ImplTraitPlaceholder
|
|
||||||
} else {
|
|
||||||
DefKind::OpaqueTy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemKind::TyAlias(..) => DefKind::TyAlias,
|
ItemKind::TyAlias(..) => DefKind::TyAlias,
|
||||||
ItemKind::Enum(..) => DefKind::Enum,
|
ItemKind::Enum(..) => DefKind::Enum,
|
||||||
ItemKind::Struct(..) => DefKind::Struct,
|
ItemKind::Struct(..) => DefKind::Struct,
|
||||||
|
|
|
@ -1050,10 +1050,6 @@ pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
|
||||||
/// there may be other effects: if the type has a validity constraint loading the place might be UB
|
/// there may be other effects: if the type has a validity constraint loading the place might be UB
|
||||||
/// if the validity constraint is not met.
|
/// if the validity constraint is not met.
|
||||||
///
|
///
|
||||||
/// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
|
|
||||||
/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
|
|
||||||
/// something we can even decide without knowing more about Rust's memory model?
|
|
||||||
///
|
|
||||||
/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri
|
/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri
|
||||||
/// currently implements it, but it seems like this may be something to check against in the
|
/// currently implements it, but it seems like this may be something to check against in the
|
||||||
/// validator.
|
/// validator.
|
||||||
|
@ -1071,6 +1067,16 @@ pub enum Operand<'tcx> {
|
||||||
/// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
|
/// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
|
||||||
/// place without first re-initializing it.
|
/// place without first re-initializing it.
|
||||||
///
|
///
|
||||||
|
/// **Needs clarification:** The operational impact of `Move` is unclear. Currently (both in
|
||||||
|
/// Miri and codegen) it has no effect at all unless it appears in an argument to `Call`; for
|
||||||
|
/// `Call` it allows the argument to be passed to the callee "in-place", i.e. the callee might
|
||||||
|
/// just get a reference to this place instead of a full copy. Miri implements this with a
|
||||||
|
/// combination of aliasing model "protectors" and putting `uninit` into the place. Ralf
|
||||||
|
/// proposes that we don't want these semantics for `Move` in regular assignments, because
|
||||||
|
/// loading a place should not have side-effects, and the aliasing model "protectors" are
|
||||||
|
/// inherently tied to a function call. Are these the semantics we want for MIR? Is this
|
||||||
|
/// something we can even decide without knowing more about Rust's memory model?
|
||||||
|
///
|
||||||
/// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
|
/// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
|
||||||
Move(Place<'tcx>),
|
Move(Place<'tcx>),
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
|
||||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
/// An unevaluated (potentially generic) constant used in the type-system.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
||||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct UnevaluatedConst<'tcx> {
|
pub struct UnevaluatedConst<'tcx> {
|
||||||
pub def: DefId,
|
pub def: DefId,
|
||||||
|
@ -35,7 +35,7 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||||
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
|
||||||
pub enum Expr<'tcx> {
|
pub enum Expr<'tcx> {
|
||||||
Binop(mir::BinOp, Const<'tcx>, Const<'tcx>),
|
Binop(mir::BinOp, Const<'tcx>, Const<'tcx>),
|
||||||
|
|
|
@ -1036,7 +1036,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
scope_def_id: LocalDefId,
|
scope_def_id: LocalDefId,
|
||||||
) -> Vec<&'tcx hir::Ty<'tcx>> {
|
) -> Vec<&'tcx hir::Ty<'tcx>> {
|
||||||
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
|
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
|
||||||
let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) else {
|
let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) =
|
||||||
|
self.hir().fn_decl_by_hir_id(hir_id)
|
||||||
|
else {
|
||||||
return vec![];
|
return vec![];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2002,16 +2004,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lower_impl_trait_in_trait_to_assoc_ty(self) -> bool {
|
|
||||||
self.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
|
pub fn is_impl_trait_in_trait(self, def_id: DefId) -> bool {
|
||||||
if self.lower_impl_trait_in_trait_to_assoc_ty() {
|
self.opt_rpitit_info(def_id).is_some()
|
||||||
self.opt_rpitit_info(def_id).is_some()
|
|
||||||
} else {
|
|
||||||
self.def_kind(def_id) == DefKind::ImplTraitPlaceholder
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Named module children from all kinds of items, including imports.
|
/// Named module children from all kinds of items, including imports.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::arena::Arena;
|
use crate::arena::Arena;
|
||||||
use rustc_data_structures::aligned::{align_of, Aligned};
|
use rustc_data_structures::aligned::{align_of, Aligned};
|
||||||
use rustc_serialize::{Encodable, Encoder};
|
use rustc_serialize::{Encodable, Encoder};
|
||||||
|
use rustc_type_ir::{InferCtxtLike, OptWithInfcx};
|
||||||
use std::alloc::Layout;
|
use std::alloc::Layout;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -119,6 +120,14 @@ impl<T: fmt::Debug> fmt::Debug for List<T> {
|
||||||
(**self).fmt(f)
|
(**self).fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
|
impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -202,6 +211,8 @@ unsafe impl<T: Sync> Sync for List<T> {}
|
||||||
// We need this since `List` uses extern type `OpaqueListContents`.
|
// We need this since `List` uses extern type `OpaqueListContents`.
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
use rustc_data_structures::sync::DynSync;
|
use rustc_data_structures::sync::DynSync;
|
||||||
|
|
||||||
|
use super::TyCtxt;
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
unsafe impl<T: DynSync> DynSync for List<T> {}
|
unsafe impl<T: DynSync> DynSync for List<T> {}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{ExpnId, ExpnKind, Span};
|
use rustc_span::{ExpnId, ExpnKind, Span};
|
||||||
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
|
||||||
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
pub use rustc_target::abi::{ReprFlags, ReprOptions};
|
||||||
|
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
pub use subst::*;
|
pub use subst::*;
|
||||||
pub use vtable::*;
|
pub use vtable::*;
|
||||||
|
|
||||||
|
@ -2688,7 +2689,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
| Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
|
| Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) => fn_def_id,
|
||||||
None => {
|
None => {
|
||||||
while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
|
while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
|
||||||
debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
|
|
||||||
def_id = self.parent(def_id);
|
def_id = self.parent(def_id);
|
||||||
}
|
}
|
||||||
def_id
|
def_id
|
||||||
|
@ -2720,26 +2720,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
|
||||||
let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
|
let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
|
||||||
|
|
||||||
if self.lower_impl_trait_in_trait_to_assoc_ty() {
|
return !self
|
||||||
return !self
|
.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
|
||||||
.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
|
.is_empty();
|
||||||
.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(RPITIT): This does a somewhat manual walk through the signature
|
|
||||||
// of the trait fn to look for any RPITITs, but that's kinda doing a lot
|
|
||||||
// of work. We can probably remove this when we refactor RPITITs to be
|
|
||||||
// associated types.
|
|
||||||
self.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| {
|
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
|
||||||
&& let ty::Alias(ty::Projection, data) = ty.kind()
|
|
||||||
&& self.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder
|
|
||||||
{
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -567,15 +567,9 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
||||||
|
|
||||||
// Alias tend to mostly already be handled downstream due to normalization.
|
// Alias tend to mostly already be handled downstream due to normalization.
|
||||||
(&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
|
(&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => {
|
||||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): This if can be removed
|
let alias_ty = relation.relate(a_data, b_data)?;
|
||||||
// and the assert uncommented once the new desugaring is stable.
|
assert_eq!(a_kind, b_kind);
|
||||||
if a_kind == b_kind {
|
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
|
||||||
let alias_ty = relation.relate(a_data, b_data)?;
|
|
||||||
// assert_eq!(a_kind, b_kind);
|
|
||||||
Ok(Ty::new_alias(tcx, a_kind, alias_ty))
|
|
||||||
} else {
|
|
||||||
Err(TypeError::Sorts(expected_found(relation, a, b)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
|
_ => Err(TypeError::Sorts(expected_found(relation, a, b))),
|
||||||
|
|
|
@ -11,13 +11,15 @@ use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
use rustc_target::abi::TyAndLayout;
|
use rustc_target::abi::TyAndLayout;
|
||||||
use rustc_type_ir::ConstKind;
|
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt::{self, Debug};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::{GenericArg, GenericArgKind, Region};
|
||||||
|
|
||||||
impl fmt::Debug for ty::TraitDef {
|
impl fmt::Debug for ty::TraitDef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
ty::tls::with(|tcx| {
|
ty::tls::with(|tcx| {
|
||||||
|
@ -89,7 +91,16 @@ impl fmt::Debug for ty::FreeRegion {
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
|
impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = self;
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
let sig = this.data;
|
||||||
|
let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig;
|
||||||
|
|
||||||
write!(f, "{}", unsafety.prefix_str())?;
|
write!(f, "{}", unsafety.prefix_str())?;
|
||||||
match abi {
|
match abi {
|
||||||
|
@ -98,15 +109,15 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "fn(")?;
|
write!(f, "fn(")?;
|
||||||
let inputs = self.inputs();
|
let inputs = sig.inputs();
|
||||||
match inputs.len() {
|
match inputs.len() {
|
||||||
0 if *c_variadic => write!(f, "...)")?,
|
0 if *c_variadic => write!(f, "...)")?,
|
||||||
0 => write!(f, ")")?,
|
0 => write!(f, ")")?,
|
||||||
_ => {
|
_ => {
|
||||||
for ty in &self.inputs()[0..(self.inputs().len() - 1)] {
|
for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] {
|
||||||
write!(f, "{ty:?}, ")?;
|
write!(f, "{:?}, ", &this.wrap(ty))?;
|
||||||
}
|
}
|
||||||
write!(f, "{:?}", self.inputs().last().unwrap())?;
|
write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?;
|
||||||
if *c_variadic {
|
if *c_variadic {
|
||||||
write!(f, "...")?;
|
write!(f, "...")?;
|
||||||
}
|
}
|
||||||
|
@ -114,9 +125,9 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.output().kind() {
|
match sig.output().kind() {
|
||||||
ty::Tuple(list) if list.is_empty() => Ok(()),
|
ty::Tuple(list) if list.is_empty() => Ok(()),
|
||||||
_ => write!(f, " -> {:?}", self.output()),
|
_ => write!(f, " -> {:?}", &this.wrap(sig.output())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,6 +144,14 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
this.data.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl<'tcx> fmt::Debug for Ty<'tcx> {
|
impl<'tcx> fmt::Debug for Ty<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
|
with_no_trimmed_paths!(fmt::Display::fmt(self, f))
|
||||||
|
@ -217,9 +236,17 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for AliasTy<'tcx> {
|
impl<'tcx> fmt::Debug for AliasTy<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
f.debug_struct("AliasTy")
|
f.debug_struct("AliasTy")
|
||||||
.field("substs", &self.substs)
|
.field("substs", &this.map(|data| data.substs))
|
||||||
.field("def_id", &self.def_id)
|
.field("def_id", &this.data.def_id)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,13 +259,93 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
use ty::InferConst::*;
|
||||||
|
match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) {
|
||||||
|
None => write!(f, "{:?}", this.data),
|
||||||
|
Some(universe) => match *this.data {
|
||||||
|
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()),
|
||||||
|
Fresh(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
match this.data {
|
||||||
|
ty::Expr::Binop(op, lhs, rhs) => {
|
||||||
|
write!(f, "({op:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs))
|
||||||
|
}
|
||||||
|
ty::Expr::UnOp(op, rhs) => write!(f, "({op:?}: {:?})", &this.wrap(rhs)),
|
||||||
|
ty::Expr::FunctionCall(func, args) => {
|
||||||
|
write!(f, "{:?}(", &this.wrap(func))?;
|
||||||
|
for arg in args.as_slice().iter().rev().skip(1).rev() {
|
||||||
|
write!(f, "{:?}, ", &this.wrap(arg))?;
|
||||||
|
}
|
||||||
|
if let Some(arg) = args.last() {
|
||||||
|
write!(f, "{:?}", &this.wrap(arg))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
ty::Expr::Cast(cast_kind, lhs, rhs) => {
|
||||||
|
write!(f, "({cast_kind:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
f.debug_struct("UnevaluatedConst")
|
||||||
|
.field("def", &this.data.def)
|
||||||
|
.field("substs", &this.wrap(this.data.substs))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
impl<'tcx> fmt::Debug for ty::Const<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
// This reflects what `Const` looked liked before `Interned` was
|
// This reflects what `Const` looked liked before `Interned` was
|
||||||
// introduced. We print it like this to avoid having to update expected
|
// introduced. We print it like this to avoid having to update expected
|
||||||
// output in a lot of tests.
|
// output in a lot of tests.
|
||||||
write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
|
write!(
|
||||||
|
f,
|
||||||
|
"Const {{ ty: {:?}, kind: {:?} }}",
|
||||||
|
&this.map(|data| data.ty()),
|
||||||
|
&this.map(|data| data.kind())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,6 +368,66 @@ impl<T: fmt::Debug> fmt::Debug for ty::Placeholder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for GenericArg<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.unpack() {
|
||||||
|
GenericArgKind::Lifetime(lt) => lt.fmt(f),
|
||||||
|
GenericArgKind::Type(ty) => ty.fmt(f),
|
||||||
|
GenericArgKind::Const(ct) => ct.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
match this.data.unpack() {
|
||||||
|
GenericArgKind::Lifetime(lt) => write!(f, "{:?}", &this.wrap(lt)),
|
||||||
|
GenericArgKind::Const(ct) => write!(f, "{:?}", &this.wrap(ct)),
|
||||||
|
GenericArgKind::Type(ty) => write!(f, "{:?}", &this.wrap(ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> fmt::Debug for Region<'tcx> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self.kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
write!(f, "{:?}", &this.map(|data| data.kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) {
|
||||||
|
Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
|
||||||
|
None => write!(f, "{:?}", this.data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
f.debug_tuple("Binder")
|
||||||
|
.field(&this.map(|data| data.as_ref().skip_binder()))
|
||||||
|
.field(&this.data.bound_vars())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Atomic structs
|
// Atomic structs
|
||||||
//
|
//
|
||||||
|
|
|
@ -35,9 +35,12 @@ use std::ops::{ControlFlow, Deref, Range};
|
||||||
use ty::util::IntTypeExt;
|
use ty::util::IntTypeExt;
|
||||||
|
|
||||||
use rustc_type_ir::sty::TyKind::*;
|
use rustc_type_ir::sty::TyKind::*;
|
||||||
|
use rustc_type_ir::CollectAndApply;
|
||||||
|
use rustc_type_ir::ConstKind as IrConstKind;
|
||||||
|
use rustc_type_ir::DebugWithInfcx;
|
||||||
|
use rustc_type_ir::DynKind;
|
||||||
|
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||||
use rustc_type_ir::TyKind as IrTyKind;
|
use rustc_type_ir::TyKind as IrTyKind;
|
||||||
use rustc_type_ir::{CollectAndApply, ConstKind as IrConstKind};
|
|
||||||
use rustc_type_ir::{DynKind, RegionKind as IrRegionKind};
|
|
||||||
|
|
||||||
use super::GenericParamDefKind;
|
use super::GenericParamDefKind;
|
||||||
|
|
||||||
|
@ -694,6 +697,15 @@ pub enum ExistentialPredicate<'tcx> {
|
||||||
AutoTrait(DefId),
|
AutoTrait(DefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
|
||||||
|
fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>(
|
||||||
|
this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
fmt::Debug::fmt(&this.data, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> ExistentialPredicate<'tcx> {
|
impl<'tcx> ExistentialPredicate<'tcx> {
|
||||||
/// Compares via an ordering that will not change if modules are reordered or other changes are
|
/// Compares via an ordering that will not change if modules are reordered or other changes are
|
||||||
/// made to the tree. In particular, this ordering is preserved across incremental compilations.
|
/// made to the tree. In particular, this ordering is preserved across incremental compilations.
|
||||||
|
@ -1237,7 +1249,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||||
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
|
||||||
match tcx.def_kind(self.def_id) {
|
match tcx.def_kind(self.def_id) {
|
||||||
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
|
DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
|
||||||
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
|
DefKind::AssocTy => ty::Projection,
|
||||||
DefKind::OpaqueTy => ty::Opaque,
|
DefKind::OpaqueTy => ty::Opaque,
|
||||||
DefKind::TyAlias => ty::Weak,
|
DefKind::TyAlias => ty::Weak,
|
||||||
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
|
||||||
|
@ -1265,9 +1277,6 @@ impl<'tcx> AliasTy<'tcx> {
|
||||||
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||||
match tcx.def_kind(self.def_id) {
|
match tcx.def_kind(self.def_id) {
|
||||||
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
|
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
|
||||||
DefKind::ImplTraitPlaceholder => {
|
|
||||||
tcx.parent(tcx.impl_trait_in_trait_parent_fn(self.def_id))
|
|
||||||
}
|
|
||||||
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
kind => bug!("expected a projection AliasTy; found {kind:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1574,12 +1583,6 @@ impl<'tcx> Deref for Region<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for Region<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{:?}", self.kind())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, PartialOrd, Ord)]
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
pub struct EarlyBoundRegion {
|
pub struct EarlyBoundRegion {
|
||||||
|
@ -1970,7 +1973,6 @@ impl<'tcx> Ty<'tcx> {
|
||||||
(kind, tcx.def_kind(alias_ty.def_id)),
|
(kind, tcx.def_kind(alias_ty.def_id)),
|
||||||
(ty::Opaque, DefKind::OpaqueTy)
|
(ty::Opaque, DefKind::OpaqueTy)
|
||||||
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
| (ty::Projection | ty::Inherent, DefKind::AssocTy)
|
||||||
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
|
|
||||||
| (ty::Weak, DefKind::TyAlias)
|
| (ty::Weak, DefKind::TyAlias)
|
||||||
);
|
);
|
||||||
Ty::new(tcx, Alias(kind, alias_ty))
|
Ty::new(tcx, Alias(kind, alias_ty))
|
||||||
|
|
|
@ -17,7 +17,6 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use core::intrinsics;
|
use core::intrinsics;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt;
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
@ -80,16 +79,6 @@ impl<'tcx> GenericArgKind<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> fmt::Debug for GenericArg<'tcx> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.unpack() {
|
|
||||||
GenericArgKind::Lifetime(lt) => lt.fmt(f),
|
|
||||||
GenericArgKind::Type(ty) => ty.fmt(f),
|
|
||||||
GenericArgKind::Const(ct) => ct.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Ord for GenericArg<'tcx> {
|
impl<'tcx> Ord for GenericArg<'tcx> {
|
||||||
fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering {
|
fn cmp(&self, other: &GenericArg<'tcx>) -> Ordering {
|
||||||
self.unpack().cmp(&other.unpack())
|
self.unpack().cmp(&other.unpack())
|
||||||
|
|
|
@ -7,11 +7,8 @@ use crate::{
|
||||||
GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
|
GenericArgKind, InternalSubsts, SubstsRef, Ty, UserSubsts,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use rustc_data_structures::{
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
fx::{FxHashMap, FxIndexMap},
|
use rustc_data_structures::unord::{UnordItems, UnordSet};
|
||||||
sync::Lrc,
|
|
||||||
unord::{UnordItems, UnordSet},
|
|
||||||
};
|
|
||||||
use rustc_errors::ErrorGuaranteed;
|
use rustc_errors::ErrorGuaranteed;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
|
@ -145,7 +142,7 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// This is used for warning unused imports. During type
|
/// This is used for warning unused imports. During type
|
||||||
/// checking, this `Lrc` should not be cloned: it must have a ref-count
|
/// checking, this `Lrc` should not be cloned: it must have a ref-count
|
||||||
/// of 1 so that we can insert things into the set mutably.
|
/// of 1 so that we can insert things into the set mutably.
|
||||||
pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
|
pub used_trait_imports: UnordSet<LocalDefId>,
|
||||||
|
|
||||||
/// If any errors occurred while type-checking this body,
|
/// If any errors occurred while type-checking this body,
|
||||||
/// this field will be set to `Some(ErrorGuaranteed)`.
|
/// this field will be set to `Some(ErrorGuaranteed)`.
|
||||||
|
@ -273,7 +270,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
liberated_fn_sigs: Default::default(),
|
liberated_fn_sigs: Default::default(),
|
||||||
fru_field_types: Default::default(),
|
fru_field_types: Default::default(),
|
||||||
coercion_casts: Default::default(),
|
coercion_casts: Default::default(),
|
||||||
used_trait_imports: Lrc::new(Default::default()),
|
used_trait_imports: Default::default(),
|
||||||
tainted_by_errors: None,
|
tainted_by_errors: None,
|
||||||
concrete_opaque_types: Default::default(),
|
concrete_opaque_types: Default::default(),
|
||||||
closure_min_captures: Default::default(),
|
closure_min_captures: Default::default(),
|
||||||
|
|
|
@ -731,11 +731,11 @@ fn switch_on_enum_discriminant<'mir, 'tcx>(
|
||||||
|
|
||||||
struct OnMutBorrow<F>(F);
|
struct OnMutBorrow<F>(F);
|
||||||
|
|
||||||
impl<F> Visitor<'_> for OnMutBorrow<F>
|
impl<'tcx, F> Visitor<'tcx> for OnMutBorrow<F>
|
||||||
where
|
where
|
||||||
F: FnMut(&mir::Place<'_>),
|
F: FnMut(&mir::Place<'tcx>),
|
||||||
{
|
{
|
||||||
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'_>, location: Location) {
|
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
|
||||||
// FIXME: Does `&raw const foo` allow mutation? See #90413.
|
// FIXME: Does `&raw const foo` allow mutation? See #90413.
|
||||||
match rvalue {
|
match rvalue {
|
||||||
mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
|
mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, place)
|
||||||
|
@ -756,7 +756,7 @@ where
|
||||||
fn for_each_mut_borrow<'tcx>(
|
fn for_each_mut_borrow<'tcx>(
|
||||||
mir: &impl MirVisitable<'tcx>,
|
mir: &impl MirVisitable<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
f: impl FnMut(&mir::Place<'_>),
|
f: impl FnMut(&mir::Place<'tcx>),
|
||||||
) {
|
) {
|
||||||
let mut vis = OnMutBorrow(f);
|
let mut vis = OnMutBorrow(f);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub mod impls;
|
||||||
pub mod move_paths;
|
pub mod move_paths;
|
||||||
pub mod rustc_peek;
|
pub mod rustc_peek;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
pub mod un_derefer;
|
||||||
pub mod value_analysis;
|
pub mod value_analysis;
|
||||||
|
|
||||||
fluent_messages! { "../messages.ftl" }
|
fluent_messages! { "../messages.ftl" }
|
||||||
|
|
|
@ -4,7 +4,6 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::abs_domain::Lift;
|
use super::abs_domain::Lift;
|
||||||
|
@ -40,22 +39,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||||
locals: body
|
locals: body
|
||||||
.local_decls
|
.local_decls
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.filter(|(_, l)| !l.is_deref_temp())
|
.map(|(i, l)| {
|
||||||
.map(|(i, _)| {
|
if l.is_deref_temp() {
|
||||||
(
|
MovePathIndex::MAX
|
||||||
i,
|
} else {
|
||||||
Self::new_move_path(
|
Self::new_move_path(
|
||||||
&mut move_paths,
|
&mut move_paths,
|
||||||
&mut path_map,
|
&mut path_map,
|
||||||
&mut init_path_map,
|
&mut init_path_map,
|
||||||
None,
|
None,
|
||||||
Place::from(i),
|
Place::from(i),
|
||||||
),
|
)
|
||||||
)
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
projections: Default::default(),
|
projections: Default::default(),
|
||||||
derefer_sidetable: Default::default(),
|
un_derefer: Default::default(),
|
||||||
},
|
},
|
||||||
move_paths,
|
move_paths,
|
||||||
path_map,
|
path_map,
|
||||||
|
@ -100,11 +99,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
///
|
///
|
||||||
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
||||||
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||||
let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref());
|
let data = &mut self.builder.data;
|
||||||
|
|
||||||
debug!("lookup({:?})", place);
|
debug!("lookup({:?})", place);
|
||||||
let mut base =
|
let mut base = data.rev_lookup.find_local(place.local);
|
||||||
self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local);
|
|
||||||
|
|
||||||
// The move path index of the first union that we find. Once this is
|
// The move path index of the first union that we find. Once this is
|
||||||
// some we stop creating child move paths, since moves from unions
|
// some we stop creating child move paths, since moves from unions
|
||||||
|
@ -113,55 +111,60 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
// from `*(u.f: &_)` isn't allowed.
|
// from `*(u.f: &_)` isn't allowed.
|
||||||
let mut union_path = None;
|
let mut union_path = None;
|
||||||
|
|
||||||
for place in deref_chain.into_iter().chain(iter::once(place)) {
|
for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) {
|
||||||
for (place_ref, elem) in place.as_ref().iter_projections() {
|
let body = self.builder.body;
|
||||||
let body = self.builder.body;
|
let tcx = self.builder.tcx;
|
||||||
let tcx = self.builder.tcx;
|
let place_ty = place_ref.ty(body, tcx).ty;
|
||||||
let place_ty = place_ref.ty(body, tcx).ty;
|
match place_ty.kind() {
|
||||||
match place_ty.kind() {
|
ty::Ref(..) | ty::RawPtr(..) => {
|
||||||
ty::Ref(..) | ty::RawPtr(..) => {
|
return Err(MoveError::cannot_move_out_of(
|
||||||
return Err(MoveError::cannot_move_out_of(
|
self.loc,
|
||||||
self.loc,
|
BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
|
||||||
BorrowedContent {
|
));
|
||||||
target_place: place_ref.project_deeper(&[elem], tcx),
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
ty::Adt(adt, _) if adt.is_union() => {
|
|
||||||
union_path.get_or_insert(base);
|
|
||||||
}
|
|
||||||
ty::Slice(_) => {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfSliceOrArray {
|
|
||||||
ty: place_ty,
|
|
||||||
is_index: matches!(elem, ProjectionElem::Index(..)),
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Array(..) => {
|
|
||||||
if let ProjectionElem::Index(..) = elem {
|
|
||||||
return Err(MoveError::cannot_move_out_of(
|
|
||||||
self.loc,
|
|
||||||
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if union_path.is_none() {
|
|
||||||
base = self
|
|
||||||
.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
|
|
||||||
}
|
}
|
||||||
|
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
ty::Adt(adt, _) if adt.is_union() => {
|
||||||
|
union_path.get_or_insert(base);
|
||||||
|
}
|
||||||
|
ty::Slice(_) => {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfSliceOrArray {
|
||||||
|
ty: place_ty,
|
||||||
|
is_index: matches!(elem, ProjectionElem::Index(..)),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Array(..) => {
|
||||||
|
if let ProjectionElem::Index(..) = elem {
|
||||||
|
return Err(MoveError::cannot_move_out_of(
|
||||||
|
self.loc,
|
||||||
|
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if union_path.is_none() {
|
||||||
|
// inlined from add_move_path because of a borrowck conflict with the iterator
|
||||||
|
base =
|
||||||
|
*data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| {
|
||||||
|
MoveDataBuilder::new_move_path(
|
||||||
|
&mut data.move_paths,
|
||||||
|
&mut data.path_map,
|
||||||
|
&mut data.init_path_map,
|
||||||
|
Some(base),
|
||||||
|
place_ref.project_deeper(&[elem], tcx),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +285,14 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
|
||||||
match &stmt.kind {
|
match &stmt.kind {
|
||||||
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
|
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
|
||||||
assert!(place.projection.is_empty());
|
let local = place.as_local().unwrap();
|
||||||
if self.builder.body.local_decls[place.local].is_deref_temp() {
|
assert!(self.builder.body.local_decls[local].is_deref_temp());
|
||||||
self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed);
|
|
||||||
}
|
let rev_lookup = &mut self.builder.data.rev_lookup;
|
||||||
|
|
||||||
|
rev_lookup.un_derefer.insert(local, reffed.as_ref());
|
||||||
|
let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local;
|
||||||
|
rev_lookup.locals[local] = rev_lookup.locals[base_local];
|
||||||
}
|
}
|
||||||
StatementKind::Assign(box (place, rval)) => {
|
StatementKind::Assign(box (place, rval)) => {
|
||||||
self.create_move_path(*place);
|
self.create_move_path(*place);
|
||||||
|
@ -306,7 +313,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
StatementKind::StorageLive(_) => {}
|
StatementKind::StorageLive(_) => {}
|
||||||
StatementKind::StorageDead(local) => {
|
StatementKind::StorageDead(local) => {
|
||||||
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
|
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
|
||||||
if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) {
|
if !self.builder.body.local_decls[*local].is_deref_temp() {
|
||||||
self.gather_move(Place::from(*local));
|
self.gather_move(Place::from(*local));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::move_paths::builder::MoveDat;
|
use crate::move_paths::builder::MoveDat;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use crate::un_derefer::UnDerefer;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_index::{IndexSlice, IndexVec};
|
use rustc_index::{IndexSlice, IndexVec};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||||
|
@ -290,7 +291,7 @@ impl Init {
|
||||||
/// Tables mapping from a place to its MovePathIndex.
|
/// Tables mapping from a place to its MovePathIndex.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MovePathLookup<'tcx> {
|
pub struct MovePathLookup<'tcx> {
|
||||||
locals: FxIndexMap<Local, MovePathIndex>,
|
locals: IndexVec<Local, MovePathIndex>,
|
||||||
|
|
||||||
/// projections are made from a base-place and a projection
|
/// projections are made from a base-place and a projection
|
||||||
/// elem. The base-place will have a unique MovePathIndex; we use
|
/// elem. The base-place will have a unique MovePathIndex; we use
|
||||||
|
@ -300,8 +301,7 @@ pub struct MovePathLookup<'tcx> {
|
||||||
/// elem to the associated MovePathIndex.
|
/// elem to the associated MovePathIndex.
|
||||||
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
|
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
|
||||||
|
|
||||||
/// Maps `DerefTemp` locals to the `Place`s assigned to them.
|
un_derefer: UnDerefer<'tcx>,
|
||||||
derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod builder;
|
mod builder;
|
||||||
|
@ -317,54 +317,23 @@ impl<'tcx> MovePathLookup<'tcx> {
|
||||||
// alternative will *not* create a MovePath on the fly for an
|
// alternative will *not* create a MovePath on the fly for an
|
||||||
// unknown place, but will rather return the nearest available
|
// unknown place, but will rather return the nearest available
|
||||||
// parent.
|
// parent.
|
||||||
pub fn find(&self, place: PlaceRef<'_>) -> LookupResult {
|
pub fn find(&self, place: PlaceRef<'tcx>) -> LookupResult {
|
||||||
let deref_chain = self.deref_chain(place);
|
let mut result = self.find_local(place.local);
|
||||||
|
|
||||||
let local = match deref_chain.first() {
|
for (_, elem) in self.un_derefer.iter_projections(place) {
|
||||||
Some(place) => place.local,
|
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
|
||||||
None => place.local,
|
result = subpath;
|
||||||
};
|
} else {
|
||||||
|
|
||||||
let mut result = *self.locals.get(&local).unwrap_or_else(|| {
|
|
||||||
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
|
|
||||||
});
|
|
||||||
|
|
||||||
// this needs to be a closure because `place` has a different lifetime than `prefix`'s places
|
|
||||||
let mut subpaths_for_place = |place: PlaceRef<'_>| {
|
|
||||||
for elem in place.projection.iter() {
|
|
||||||
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
|
|
||||||
result = subpath;
|
|
||||||
} else {
|
|
||||||
return Some(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for place in deref_chain {
|
|
||||||
if let Some(result) = subpaths_for_place(place.as_ref()) {
|
|
||||||
return LookupResult::Parent(Some(result));
|
return LookupResult::Parent(Some(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = subpaths_for_place(place) {
|
|
||||||
return LookupResult::Parent(Some(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
LookupResult::Exact(result)
|
LookupResult::Exact(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
pub fn find_local(&self, local: Local) -> MovePathIndex {
|
||||||
let deref_chain = self.deref_chain(Place::from(local).as_ref());
|
self.locals[local]
|
||||||
|
|
||||||
let local = match deref_chain.last() {
|
|
||||||
Some(place) => place.local,
|
|
||||||
None => local,
|
|
||||||
};
|
|
||||||
|
|
||||||
*self.locals.get(&local).unwrap_or_else(|| {
|
|
||||||
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An enumerated iterator of `local`s and their associated
|
/// An enumerated iterator of `local`s and their associated
|
||||||
|
@ -372,22 +341,7 @@ impl<'tcx> MovePathLookup<'tcx> {
|
||||||
pub fn iter_locals_enumerated(
|
pub fn iter_locals_enumerated(
|
||||||
&self,
|
&self,
|
||||||
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
|
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
|
||||||
self.locals.iter().map(|(&l, &idx)| (l, idx))
|
self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the chain of places behind `DerefTemp` locals in `place`
|
|
||||||
pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> {
|
|
||||||
let mut prefix = Vec::new();
|
|
||||||
let mut local = place.local;
|
|
||||||
|
|
||||||
while let Some(&reffed) = self.derefer_sidetable.get(&local) {
|
|
||||||
prefix.insert(0, reffed);
|
|
||||||
local = reffed.local;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("deref_chain({place:?}) = {prefix:?}");
|
|
||||||
|
|
||||||
prefix
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
compiler/rustc_mir_dataflow/src/un_derefer.rs
Normal file
100
compiler/rustc_mir_dataflow/src/un_derefer.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_middle::mir::*;
|
||||||
|
|
||||||
|
/// Used for reverting changes made by `DerefSeparator`
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct UnDerefer<'tcx> {
|
||||||
|
deref_chains: FxHashMap<Local, Vec<PlaceRef<'tcx>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> UnDerefer<'tcx> {
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) {
|
||||||
|
let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default();
|
||||||
|
chain.push(reffed);
|
||||||
|
self.deref_chains.insert(local, chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the chain of places behind `DerefTemp` locals
|
||||||
|
#[inline]
|
||||||
|
pub fn deref_chain(&self, local: Local) -> &[PlaceRef<'tcx>] {
|
||||||
|
self.deref_chains.get(&local).map(Vec::as_slice).unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over the projections of a place and its deref chain.
|
||||||
|
///
|
||||||
|
/// See [`PlaceRef::iter_projections`]
|
||||||
|
#[inline]
|
||||||
|
pub fn iter_projections(
|
||||||
|
&self,
|
||||||
|
place: PlaceRef<'tcx>,
|
||||||
|
) -> impl Iterator<Item = (PlaceRef<'tcx>, PlaceElem<'tcx>)> + '_ {
|
||||||
|
ProjectionIter::new(self.deref_chain(place.local), place)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The iterator returned by [`UnDerefer::iter_projections`].
|
||||||
|
struct ProjectionIter<'a, 'tcx> {
|
||||||
|
places: SlicePlusOne<'a, PlaceRef<'tcx>>,
|
||||||
|
proj_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> ProjectionIter<'a, 'tcx> {
|
||||||
|
#[inline]
|
||||||
|
fn new(deref_chain: &'a [PlaceRef<'tcx>], place: PlaceRef<'tcx>) -> Self {
|
||||||
|
// just return an empty iterator for a bare local
|
||||||
|
let last = if place.as_local().is_none() {
|
||||||
|
Some(place)
|
||||||
|
} else {
|
||||||
|
debug_assert!(deref_chain.is_empty());
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectionIter { places: SlicePlusOne { slice: deref_chain, last }, proj_idx: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Iterator for ProjectionIter<'_, 'tcx> {
|
||||||
|
type Item = (PlaceRef<'tcx>, PlaceElem<'tcx>);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
|
||||||
|
let place = self.places.read()?;
|
||||||
|
|
||||||
|
// the projection should never be empty except for a bare local which is handled in new
|
||||||
|
let partial_place =
|
||||||
|
PlaceRef { local: place.local, projection: &place.projection[..self.proj_idx] };
|
||||||
|
let elem = place.projection[self.proj_idx];
|
||||||
|
|
||||||
|
if self.proj_idx == place.projection.len() - 1 {
|
||||||
|
self.proj_idx = 0;
|
||||||
|
self.places.advance();
|
||||||
|
} else {
|
||||||
|
self.proj_idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some((partial_place, elem))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SlicePlusOne<'a, T> {
|
||||||
|
slice: &'a [T],
|
||||||
|
last: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy> SlicePlusOne<'_, T> {
|
||||||
|
#[inline]
|
||||||
|
fn read(&self) -> Option<T> {
|
||||||
|
self.slice.first().copied().or(self.last)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn advance(&mut self) {
|
||||||
|
match self.slice {
|
||||||
|
[_, ref remainder @ ..] => {
|
||||||
|
self.slice = remainder;
|
||||||
|
}
|
||||||
|
[] => self.last = None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,8 +22,8 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
|
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
use rustc_const_eval::interpret::{
|
use rustc_const_eval::interpret::{
|
||||||
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, Frame, ImmTy, Immediate,
|
self, compile_time_machine, AllocId, ConstAllocation, ConstValue, FnArg, Frame, ImmTy,
|
||||||
InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
|
Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
|
||||||
StackPopCleanup,
|
StackPopCleanup,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_instance: ty::Instance<'tcx>,
|
_instance: ty::Instance<'tcx>,
|
||||||
_abi: CallAbi,
|
_abi: CallAbi,
|
||||||
_args: &[OpTy<'tcx>],
|
_args: &[FnArg<'tcx>],
|
||||||
_destination: &PlaceTy<'tcx>,
|
_destination: &PlaceTy<'tcx>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: UnwindAction,
|
_unwind: UnwindAction,
|
||||||
|
|
|
@ -532,7 +532,7 @@ impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
|
||||||
|
|
||||||
struct DummyMachine;
|
struct DummyMachine;
|
||||||
|
|
||||||
impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine {
|
impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachine {
|
||||||
rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>);
|
rustc_const_eval::interpret::compile_time_machine!(<'mir, 'tcx>);
|
||||||
type MemoryKind = !;
|
type MemoryKind = !;
|
||||||
const PANIC_ON_ALLOC_FAIL: bool = true;
|
const PANIC_ON_ALLOC_FAIL: bool = true;
|
||||||
|
@ -557,7 +557,7 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_instance: ty::Instance<'tcx>,
|
_instance: ty::Instance<'tcx>,
|
||||||
_abi: rustc_target::spec::abi::Abi,
|
_abi: rustc_target::spec::abi::Abi,
|
||||||
_args: &[rustc_const_eval::interpret::OpTy<'tcx, Self::Provenance>],
|
_args: &[rustc_const_eval::interpret::FnArg<'tcx, Self::Provenance>],
|
||||||
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
_destination: &rustc_const_eval::interpret::PlaceTy<'tcx, Self::Provenance>,
|
||||||
_target: Option<BasicBlock>,
|
_target: Option<BasicBlock>,
|
||||||
_unwind: UnwindAction,
|
_unwind: UnwindAction,
|
||||||
|
|
|
@ -163,7 +163,6 @@ fn mark_used_by_default_parameters<'tcx>(
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::LifetimeParam
|
| DefKind::LifetimeParam
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
|
|
|
@ -694,7 +694,6 @@ impl CheckAttrVisitor<'_> {
|
||||||
| Target::GlobalAsm
|
| Target::GlobalAsm
|
||||||
| Target::TyAlias
|
| Target::TyAlias
|
||||||
| Target::OpaqueTy
|
| Target::OpaqueTy
|
||||||
| Target::ImplTraitPlaceholder
|
|
||||||
| Target::Enum
|
| Target::Enum
|
||||||
| Target::Variant
|
| Target::Variant
|
||||||
| Target::Struct
|
| Target::Struct
|
||||||
|
|
|
@ -136,19 +136,7 @@ where
|
||||||
|
|
||||||
fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
|
fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
|
||||||
let tcx = self.def_id_visitor.tcx();
|
let tcx = self.def_id_visitor.tcx();
|
||||||
let (trait_ref, assoc_substs) = if tcx.def_kind(projection.def_id)
|
let (trait_ref, assoc_substs) = projection.trait_ref_and_own_substs(tcx);
|
||||||
!= DefKind::ImplTraitPlaceholder
|
|
||||||
{
|
|
||||||
projection.trait_ref_and_own_substs(tcx)
|
|
||||||
} else {
|
|
||||||
// HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
|
|
||||||
let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id);
|
|
||||||
let trait_generics = tcx.generics_of(def_id);
|
|
||||||
(
|
|
||||||
ty::TraitRef::new(tcx, def_id, projection.substs.truncate_to(tcx, trait_generics)),
|
|
||||||
&projection.substs[trait_generics.count()..],
|
|
||||||
)
|
|
||||||
};
|
|
||||||
self.visit_trait(trait_ref)?;
|
self.visit_trait(trait_ref)?;
|
||||||
if V::SHALLOW {
|
if V::SHALLOW {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
|
@ -651,7 +639,6 @@ impl<'tcx> EmbargoVisitor<'tcx> {
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::Fn
|
| DefKind::Fn
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::AssocFn
|
| DefKind::AssocFn
|
||||||
| DefKind::Trait
|
| DefKind::Trait
|
||||||
| DefKind::TyParam
|
| DefKind::TyParam
|
||||||
|
|
|
@ -949,7 +949,6 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
| DefKind::TyAlias
|
| DefKind::TyAlias
|
||||||
| DefKind::ForeignTy
|
| DefKind::ForeignTy
|
||||||
| DefKind::OpaqueTy
|
| DefKind::OpaqueTy
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::TraitAlias
|
| DefKind::TraitAlias
|
||||||
| DefKind::AssocTy,
|
| DefKind::AssocTy,
|
||||||
_,
|
_,
|
||||||
|
|
|
@ -3503,7 +3503,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
let report_errors = |this: &mut Self, res: Option<Res>| {
|
let report_errors = |this: &mut Self, res: Option<Res>| {
|
||||||
if this.should_report_errs() {
|
if this.should_report_errs() {
|
||||||
let (err, candidates) =
|
let (err, candidates) =
|
||||||
this.smart_resolve_report_errors(path, path, path_span, source, res);
|
this.smart_resolve_report_errors(path, None, path_span, source, res);
|
||||||
|
|
||||||
let def_id = this.parent_scope.module.nearest_parent_mod();
|
let def_id = this.parent_scope.module.nearest_parent_mod();
|
||||||
let instead = res.is_some();
|
let instead = res.is_some();
|
||||||
|
@ -3555,14 +3555,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||||
// Before we start looking for candidates, we have to get our hands
|
// Before we start looking for candidates, we have to get our hands
|
||||||
// on the type user is trying to perform invocation on; basically:
|
// on the type user is trying to perform invocation on; basically:
|
||||||
// we're transforming `HashMap::new` into just `HashMap`.
|
// we're transforming `HashMap::new` into just `HashMap`.
|
||||||
let prefix_path = match path.split_last() {
|
let (following_seg, prefix_path) = match path.split_last() {
|
||||||
Some((_, path)) if !path.is_empty() => path,
|
Some((last, path)) if !path.is_empty() => (Some(last), path),
|
||||||
_ => return Some(parent_err),
|
_ => return Some(parent_err),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut err, candidates) = this.smart_resolve_report_errors(
|
let (mut err, candidates) = this.smart_resolve_report_errors(
|
||||||
prefix_path,
|
prefix_path,
|
||||||
path,
|
following_seg,
|
||||||
path_span,
|
path_span,
|
||||||
PathSource::Type,
|
PathSource::Type,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -332,15 +332,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
pub(crate) fn smart_resolve_partial_mod_path_errors(
|
pub(crate) fn smart_resolve_partial_mod_path_errors(
|
||||||
&mut self,
|
&mut self,
|
||||||
prefix_path: &[Segment],
|
prefix_path: &[Segment],
|
||||||
path: &[Segment],
|
following_seg: Option<&Segment>,
|
||||||
) -> Vec<ImportSuggestion> {
|
) -> Vec<ImportSuggestion> {
|
||||||
let next_seg = if path.len() >= prefix_path.len() + 1 && prefix_path.len() == 1 {
|
|
||||||
path.get(prefix_path.len())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
if let Some(segment) = prefix_path.last() &&
|
if let Some(segment) = prefix_path.last() &&
|
||||||
let Some(next_seg) = next_seg {
|
let Some(following_seg) = following_seg
|
||||||
|
{
|
||||||
let candidates = self.r.lookup_import_candidates(
|
let candidates = self.r.lookup_import_candidates(
|
||||||
segment.ident,
|
segment.ident,
|
||||||
Namespace::TypeNS,
|
Namespace::TypeNS,
|
||||||
|
@ -353,9 +349,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
.filter(|candidate| {
|
.filter(|candidate| {
|
||||||
if let Some(def_id) = candidate.did &&
|
if let Some(def_id) = candidate.did &&
|
||||||
let Some(module) = self.r.get_module(def_id) {
|
let Some(module) = self.r.get_module(def_id) {
|
||||||
self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
|
Some(def_id) != self.parent_scope.module.opt_def_id() &&
|
||||||
key.ident.name == next_seg.ident.name
|
self.r.resolutions(module).borrow().iter().any(|(key, _r)| {
|
||||||
})
|
key.ident.name == following_seg.ident.name
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -371,7 +368,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
pub(crate) fn smart_resolve_report_errors(
|
pub(crate) fn smart_resolve_report_errors(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
full_path: &[Segment],
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
source: PathSource<'_>,
|
source: PathSource<'_>,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
|
@ -412,8 +409,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
return (err, Vec::new());
|
return (err, Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (found, candidates) =
|
let (found, candidates) = self.try_lookup_name_relaxed(
|
||||||
self.try_lookup_name_relaxed(&mut err, source, path, full_path, span, res, &base_error);
|
&mut err,
|
||||||
|
source,
|
||||||
|
path,
|
||||||
|
following_seg,
|
||||||
|
span,
|
||||||
|
res,
|
||||||
|
&base_error,
|
||||||
|
);
|
||||||
if found {
|
if found {
|
||||||
return (err, candidates);
|
return (err, candidates);
|
||||||
}
|
}
|
||||||
|
@ -422,7 +426,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
|
|
||||||
// if we have suggested using pattern matching, then don't add needless suggestions
|
// if we have suggested using pattern matching, then don't add needless suggestions
|
||||||
// for typos.
|
// for typos.
|
||||||
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
|
fallback |= self.suggest_typo(&mut err, source, path, following_seg, span, &base_error);
|
||||||
|
|
||||||
if fallback {
|
if fallback {
|
||||||
// Fallback label.
|
// Fallback label.
|
||||||
|
@ -519,7 +523,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
source: PathSource<'_>,
|
source: PathSource<'_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
full_path: &[Segment],
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
res: Option<Res>,
|
res: Option<Res>,
|
||||||
base_error: &BaseError,
|
base_error: &BaseError,
|
||||||
|
@ -590,8 +594,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try finding a suitable replacement.
|
// Try finding a suitable replacement.
|
||||||
let typo_sugg =
|
let typo_sugg = self
|
||||||
self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion();
|
.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected)
|
||||||
|
.to_opt_suggestion();
|
||||||
if path.len() == 1 && self.self_type_is_available() {
|
if path.len() == 1 && self.self_type_is_available() {
|
||||||
if let Some(candidate) =
|
if let Some(candidate) =
|
||||||
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
|
self.lookup_assoc_candidate(ident, ns, is_expected, source.is_call())
|
||||||
|
@ -690,7 +695,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
candidates = self.smart_resolve_partial_mod_path_errors(path, full_path);
|
candidates = self.smart_resolve_partial_mod_path_errors(path, following_seg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (false, candidates);
|
return (false, candidates);
|
||||||
|
@ -776,12 +781,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
source: PathSource<'_>,
|
source: PathSource<'_>,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
|
following_seg: Option<&Segment>,
|
||||||
span: Span,
|
span: Span,
|
||||||
base_error: &BaseError,
|
base_error: &BaseError,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let is_expected = &|res| source.is_expected(res);
|
let is_expected = &|res| source.is_expected(res);
|
||||||
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
|
||||||
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
|
let typo_sugg =
|
||||||
|
self.lookup_typo_candidate(path, following_seg, source.namespace(), is_expected);
|
||||||
let is_in_same_file = &|sp1, sp2| {
|
let is_in_same_file = &|sp1, sp2| {
|
||||||
let source_map = self.r.tcx.sess.source_map();
|
let source_map = self.r.tcx.sess.source_map();
|
||||||
let file1 = source_map.span_to_filename(sp1);
|
let file1 = source_map.span_to_filename(sp1);
|
||||||
|
@ -1715,6 +1722,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
fn lookup_typo_candidate(
|
fn lookup_typo_candidate(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &[Segment],
|
path: &[Segment],
|
||||||
|
following_seg: Option<&Segment>,
|
||||||
ns: Namespace,
|
ns: Namespace,
|
||||||
filter_fn: &impl Fn(Res) -> bool,
|
filter_fn: &impl Fn(Res) -> bool,
|
||||||
) -> TypoCandidate {
|
) -> TypoCandidate {
|
||||||
|
@ -1793,6 +1801,26 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if next_seg is present, let's filter everything that does not continue the path
|
||||||
|
if let Some(following_seg) = following_seg {
|
||||||
|
names.retain(|suggestion| match suggestion.res {
|
||||||
|
Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _) => {
|
||||||
|
// FIXME: this is not totally accurate, but mostly works
|
||||||
|
suggestion.candidate != following_seg.ident.name
|
||||||
|
}
|
||||||
|
Res::Def(DefKind::Mod, def_id) => self.r.get_module(def_id).map_or_else(
|
||||||
|
|| false,
|
||||||
|
|module| {
|
||||||
|
self.r
|
||||||
|
.resolutions(module)
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.any(|(key, _)| key.ident.name == following_seg.ident.name)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
}
|
||||||
let name = path[path.len() - 1].ident.name;
|
let name = path[path.len() - 1].ident.name;
|
||||||
// Make sure error reporting is deterministic.
|
// Make sure error reporting is deterministic.
|
||||||
names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
|
names.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));
|
||||||
|
|
|
@ -1583,9 +1583,6 @@ options! {
|
||||||
"what location details should be tracked when using caller_location, either \
|
"what location details should be tracked when using caller_location, either \
|
||||||
`none`, or a comma separated list of location details, for which \
|
`none`, or a comma separated list of location details, for which \
|
||||||
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
|
valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
|
||||||
lower_impl_trait_in_trait_to_assoc_ty: bool = (false, parse_bool, [TRACKED],
|
|
||||||
"modify the lowering strategy for `impl Trait` in traits so that they are lowered to \
|
|
||||||
generic associated types"),
|
|
||||||
ls: bool = (false, parse_bool, [UNTRACKED],
|
ls: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"list the symbols defined by a library crate (default: no)"),
|
"list the symbols defined by a library crate (default: no)"),
|
||||||
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
|
macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
|
|
@ -4,14 +4,18 @@ version = "0.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
# Use optional dependencies for rustc_* in order to support building this crate separately.
|
||||||
|
rustc_hir = { path = "../rustc_hir", optional = true }
|
||||||
rustc_middle = { path = "../rustc_middle", optional = true }
|
rustc_middle = { path = "../rustc_middle", optional = true }
|
||||||
rustc_span = { path = "../rustc_span", optional = true }
|
rustc_span = { path = "../rustc_span", optional = true }
|
||||||
|
rustc_target = { path = "../rustc_target", optional = true }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
scoped-tls = "1.0"
|
scoped-tls = "1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = [
|
||||||
|
"rustc_hir",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
"rustc_target",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "nightly-2023-02-28"
|
channel = "nightly-2023-06-14"
|
||||||
components = [ "rustfmt", "rustc-dev" ]
|
components = [ "rustfmt", "rustc-dev" ]
|
||||||
|
|
|
@ -13,6 +13,17 @@
|
||||||
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
|
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
|
||||||
#![feature(local_key_cell_methods)]
|
#![feature(local_key_cell_methods)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
|
#![feature(type_alias_impl_trait)] // Used to define opaque types.
|
||||||
|
|
||||||
|
// Declare extern rustc_* crates to enable building this crate separately from the compiler.
|
||||||
|
#[cfg(not(feature = "default"))]
|
||||||
|
extern crate rustc_hir;
|
||||||
|
#[cfg(not(feature = "default"))]
|
||||||
|
extern crate rustc_middle;
|
||||||
|
#[cfg(not(feature = "default"))]
|
||||||
|
extern crate rustc_span;
|
||||||
|
#[cfg(not(feature = "default"))]
|
||||||
|
extern crate rustc_target;
|
||||||
|
|
||||||
pub mod rustc_internal;
|
pub mod rustc_internal;
|
||||||
pub mod stable_mir;
|
pub mod stable_mir;
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
|
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
|
||||||
//! until stable MIR is complete.
|
//! until stable MIR is complete.
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::string::ToString;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
rustc_smir::Tables,
|
rustc_smir::Tables,
|
||||||
stable_mir::{self, with},
|
stable_mir::{self, with},
|
||||||
|
@ -49,3 +52,10 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
|
||||||
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
|
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
|
||||||
crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
|
crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type that provides internal information but that can still be used for debug purpose.
|
||||||
|
pub type Opaque = impl Debug + ToString + Clone;
|
||||||
|
|
||||||
|
pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque {
|
||||||
|
format!("{value:?}")
|
||||||
|
}
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
//!
|
//!
|
||||||
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
|
||||||
|
|
||||||
|
use crate::rustc_internal::{self, opaque};
|
||||||
use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
use crate::stable_mir::ty::{FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
||||||
use crate::stable_mir::{self, Context};
|
use crate::stable_mir::{self, Context};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
|
use rustc_target::abi::FieldIdx;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
impl<'tcx> Context for Tables<'tcx> {
|
impl<'tcx> Context for Tables<'tcx> {
|
||||||
|
@ -137,11 +139,21 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
|
||||||
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Stable {
|
/// Trait used to convert between an internal MIR type to a Stable MIR type.
|
||||||
|
pub(crate) trait Stable {
|
||||||
|
/// The stable representation of the type implementing Stable.
|
||||||
type T;
|
type T;
|
||||||
|
/// Converts an object to the equivalent Stable MIR representation.
|
||||||
fn stable(&self) -> Self::T;
|
fn stable(&self) -> Self::T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Stable for DefId {
|
||||||
|
type T = stable_mir::CrateItem;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
rustc_internal::crate_item(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable for mir::Statement<'tcx> {
|
impl<'tcx> Stable for mir::Statement<'tcx> {
|
||||||
type T = stable_mir::mir::Statement;
|
type T = stable_mir::mir::Statement;
|
||||||
fn stable(&self) -> Self::T {
|
fn stable(&self) -> Self::T {
|
||||||
|
@ -173,12 +185,18 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
Use(op) => stable_mir::mir::Rvalue::Use(op.stable()),
|
Use(op) => stable_mir::mir::Rvalue::Use(op.stable()),
|
||||||
Repeat(_, _) => todo!(),
|
Repeat(_, _) => todo!(),
|
||||||
Ref(_, _, _) => todo!(),
|
Ref(region, kind, place) => {
|
||||||
ThreadLocalRef(_) => todo!(),
|
stable_mir::mir::Rvalue::Ref(opaque(region), kind.stable(), place.stable())
|
||||||
AddressOf(_, _) => todo!(),
|
}
|
||||||
Len(_) => todo!(),
|
ThreadLocalRef(def_id) => stable_mir::mir::Rvalue::ThreadLocalRef(def_id.stable()),
|
||||||
|
AddressOf(mutability, place) => {
|
||||||
|
stable_mir::mir::Rvalue::AddressOf(mutability.stable(), place.stable())
|
||||||
|
}
|
||||||
|
Len(place) => stable_mir::mir::Rvalue::Len(place.stable()),
|
||||||
Cast(_, _, _) => todo!(),
|
Cast(_, _, _) => todo!(),
|
||||||
BinaryOp(_, _) => todo!(),
|
BinaryOp(bin_op, ops) => {
|
||||||
|
stable_mir::mir::Rvalue::BinaryOp(bin_op.stable(), ops.0.stable(), ops.1.stable())
|
||||||
|
}
|
||||||
CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
|
CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
|
||||||
bin_op.stable(),
|
bin_op.stable(),
|
||||||
ops.0.stable(),
|
ops.0.stable(),
|
||||||
|
@ -186,14 +204,119 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> {
|
||||||
),
|
),
|
||||||
NullaryOp(_, _) => todo!(),
|
NullaryOp(_, _) => todo!(),
|
||||||
UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()),
|
UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()),
|
||||||
Discriminant(_) => todo!(),
|
Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable()),
|
||||||
Aggregate(_, _) => todo!(),
|
Aggregate(_, _) => todo!(),
|
||||||
ShallowInitBox(_, _) => todo!(),
|
ShallowInitBox(_, _) => todo!(),
|
||||||
CopyForDeref(_) => todo!(),
|
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Stable for mir::Mutability {
|
||||||
|
type T = stable_mir::mir::Mutability;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use mir::Mutability::*;
|
||||||
|
match *self {
|
||||||
|
Not => stable_mir::mir::Mutability::Not,
|
||||||
|
Mut => stable_mir::mir::Mutability::Mut,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for mir::BorrowKind {
|
||||||
|
type T = stable_mir::mir::BorrowKind;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use mir::BorrowKind::*;
|
||||||
|
match *self {
|
||||||
|
Shared => stable_mir::mir::BorrowKind::Shared,
|
||||||
|
Shallow => stable_mir::mir::BorrowKind::Shallow,
|
||||||
|
Mut { kind } => stable_mir::mir::BorrowKind::Mut { kind: kind.stable() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for mir::MutBorrowKind {
|
||||||
|
type T = stable_mir::mir::MutBorrowKind;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use mir::MutBorrowKind::*;
|
||||||
|
match *self {
|
||||||
|
Default => stable_mir::mir::MutBorrowKind::Default,
|
||||||
|
TwoPhaseBorrow => stable_mir::mir::MutBorrowKind::TwoPhaseBorrow,
|
||||||
|
ClosureCapture => stable_mir::mir::MutBorrowKind::ClosureCapture,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Stable for mir::NullOp<'tcx> {
|
||||||
|
type T = stable_mir::mir::NullOp;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use mir::NullOp::*;
|
||||||
|
match self {
|
||||||
|
SizeOf => stable_mir::mir::NullOp::SizeOf,
|
||||||
|
AlignOf => stable_mir::mir::NullOp::AlignOf,
|
||||||
|
OffsetOf(indices) => {
|
||||||
|
stable_mir::mir::NullOp::OffsetOf(indices.iter().map(|idx| idx.stable()).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for mir::CastKind {
|
||||||
|
type T = stable_mir::mir::CastKind;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use mir::CastKind::*;
|
||||||
|
match self {
|
||||||
|
PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
|
||||||
|
PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
|
||||||
|
PointerCoercion(c) => stable_mir::mir::CastKind::PointerCoercion(c.stable()),
|
||||||
|
DynStar => stable_mir::mir::CastKind::DynStar,
|
||||||
|
IntToInt => stable_mir::mir::CastKind::IntToInt,
|
||||||
|
FloatToInt => stable_mir::mir::CastKind::FloatToInt,
|
||||||
|
FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
|
||||||
|
IntToFloat => stable_mir::mir::CastKind::IntToFloat,
|
||||||
|
PtrToPtr => stable_mir::mir::CastKind::PtrToPtr,
|
||||||
|
FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr,
|
||||||
|
Transmute => stable_mir::mir::CastKind::Transmute,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for ty::adjustment::PointerCoercion {
|
||||||
|
type T = stable_mir::mir::PointerCoercion;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
use ty::adjustment::PointerCoercion;
|
||||||
|
match self {
|
||||||
|
PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
|
||||||
|
PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
|
||||||
|
PointerCoercion::ClosureFnPointer(unsafety) => {
|
||||||
|
stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable())
|
||||||
|
}
|
||||||
|
PointerCoercion::MutToConstPointer => {
|
||||||
|
stable_mir::mir::PointerCoercion::MutToConstPointer
|
||||||
|
}
|
||||||
|
PointerCoercion::ArrayToPointer => stable_mir::mir::PointerCoercion::ArrayToPointer,
|
||||||
|
PointerCoercion::Unsize => stable_mir::mir::PointerCoercion::Unsize,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for rustc_hir::Unsafety {
|
||||||
|
type T = stable_mir::mir::Safety;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
match self {
|
||||||
|
rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
|
||||||
|
rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stable for FieldIdx {
|
||||||
|
type T = usize;
|
||||||
|
fn stable(&self) -> Self::T {
|
||||||
|
self.as_usize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable for mir::Operand<'tcx> {
|
impl<'tcx> Stable for mir::Operand<'tcx> {
|
||||||
type T = stable_mir::mir::Operand;
|
type T = stable_mir::mir::Operand;
|
||||||
fn stable(&self) -> Self::T {
|
fn stable(&self) -> Self::T {
|
||||||
|
@ -229,34 +352,38 @@ impl Stable for mir::UnwindAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rustc_assert_msg_to_msg<'tcx>(
|
impl<'tcx> Stable for mir::AssertMessage<'tcx> {
|
||||||
assert_message: &rustc_middle::mir::AssertMessage<'tcx>,
|
type T = stable_mir::mir::AssertMessage;
|
||||||
) -> stable_mir::mir::AssertMessage {
|
fn stable(&self) -> Self::T {
|
||||||
use rustc_middle::mir::AssertKind;
|
use rustc_middle::mir::AssertKind;
|
||||||
match assert_message {
|
match self {
|
||||||
AssertKind::BoundsCheck { len, index } => {
|
AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
|
||||||
stable_mir::mir::AssertMessage::BoundsCheck { len: len.stable(), index: index.stable() }
|
len: len.stable(),
|
||||||
}
|
index: index.stable(),
|
||||||
AssertKind::Overflow(bin_op, op1, op2) => {
|
},
|
||||||
stable_mir::mir::AssertMessage::Overflow(bin_op.stable(), op1.stable(), op2.stable())
|
AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
|
||||||
}
|
bin_op.stable(),
|
||||||
AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()),
|
op1.stable(),
|
||||||
AssertKind::DivisionByZero(op) => {
|
op2.stable(),
|
||||||
stable_mir::mir::AssertMessage::DivisionByZero(op.stable())
|
),
|
||||||
}
|
AssertKind::OverflowNeg(op) => stable_mir::mir::AssertMessage::OverflowNeg(op.stable()),
|
||||||
AssertKind::RemainderByZero(op) => {
|
AssertKind::DivisionByZero(op) => {
|
||||||
stable_mir::mir::AssertMessage::RemainderByZero(op.stable())
|
stable_mir::mir::AssertMessage::DivisionByZero(op.stable())
|
||||||
}
|
}
|
||||||
AssertKind::ResumedAfterReturn(generator) => {
|
AssertKind::RemainderByZero(op) => {
|
||||||
stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable())
|
stable_mir::mir::AssertMessage::RemainderByZero(op.stable())
|
||||||
}
|
}
|
||||||
AssertKind::ResumedAfterPanic(generator) => {
|
AssertKind::ResumedAfterReturn(generator) => {
|
||||||
stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable())
|
stable_mir::mir::AssertMessage::ResumedAfterReturn(generator.stable())
|
||||||
}
|
}
|
||||||
AssertKind::MisalignedPointerDereference { required, found } => {
|
AssertKind::ResumedAfterPanic(generator) => {
|
||||||
stable_mir::mir::AssertMessage::MisalignedPointerDereference {
|
stable_mir::mir::AssertMessage::ResumedAfterPanic(generator.stable())
|
||||||
required: required.stable(),
|
}
|
||||||
found: found.stable(),
|
AssertKind::MisalignedPointerDereference { required, found } => {
|
||||||
|
stable_mir::mir::AssertMessage::MisalignedPointerDereference {
|
||||||
|
required: required.stable(),
|
||||||
|
found: found.stable(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +508,7 @@ impl<'tcx> Stable for mir::Terminator<'tcx> {
|
||||||
Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
|
Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
|
||||||
cond: cond.stable(),
|
cond: cond.stable(),
|
||||||
expected: *expected,
|
expected: *expected,
|
||||||
msg: rustc_assert_msg_to_msg(msg),
|
msg: msg.stable(),
|
||||||
target: target.as_usize(),
|
target: target.as_usize(),
|
||||||
unwind: unwind.stable(),
|
unwind: unwind.stable(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::stable_mir::ty::Ty;
|
use crate::rustc_internal::Opaque;
|
||||||
|
use crate::stable_mir::{self, ty::Ty};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
|
@ -136,12 +137,98 @@ pub enum Statement {
|
||||||
Nop,
|
Nop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Region = Opaque;
|
||||||
|
|
||||||
// FIXME this is incomplete
|
// FIXME this is incomplete
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Rvalue {
|
pub enum Rvalue {
|
||||||
Use(Operand),
|
/// Creates a pointer with the indicated mutability to the place.
|
||||||
|
///
|
||||||
|
/// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
|
||||||
|
/// `&raw v` or `addr_of!(v)`.
|
||||||
|
AddressOf(Mutability, Place),
|
||||||
|
|
||||||
|
/// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
|
||||||
|
/// parameter may be a `usize` as well.
|
||||||
|
/// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
|
||||||
|
/// raw pointers, or function pointers and return a `bool`. The types of the operands must be
|
||||||
|
/// matching, up to the usual caveat of the lifetimes in function pointers.
|
||||||
|
/// * Left and right shift operations accept signed or unsigned integers not necessarily of the
|
||||||
|
/// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
|
||||||
|
/// truncated as needed.
|
||||||
|
/// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
|
||||||
|
/// types and return a value of that type.
|
||||||
|
/// * The remaining operations accept signed integers, unsigned integers, or floats with
|
||||||
|
/// matching types and return a value of that type.
|
||||||
|
BinaryOp(BinOp, Operand, Operand),
|
||||||
|
|
||||||
|
/// Performs essentially all of the casts that can be performed via `as`.
|
||||||
|
///
|
||||||
|
/// This allows for casts from/to a variety of types.
|
||||||
|
Cast(CastKind, Operand, Ty),
|
||||||
|
|
||||||
|
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
|
||||||
|
///
|
||||||
|
/// For addition, subtraction, and multiplication on integers the error condition is set when
|
||||||
|
/// the infinite precision result would not be equal to the actual result.
|
||||||
CheckedBinaryOp(BinOp, Operand, Operand),
|
CheckedBinaryOp(BinOp, Operand, Operand),
|
||||||
|
|
||||||
|
/// A CopyForDeref is equivalent to a read from a place.
|
||||||
|
/// When such a read happens, it is guaranteed that the only use of the returned value is a
|
||||||
|
/// deref operation, immediately followed by one or more projections.
|
||||||
|
CopyForDeref(Place),
|
||||||
|
|
||||||
|
/// Computes the discriminant of the place, returning it as an integer of type
|
||||||
|
/// [`discriminant_ty`]. Returns zero for types without discriminant.
|
||||||
|
///
|
||||||
|
/// The validity requirements for the underlying value are undecided for this rvalue, see
|
||||||
|
/// [#91095]. Note too that the value of the discriminant is not the same thing as the
|
||||||
|
/// variant index; use [`discriminant_for_variant`] to convert.
|
||||||
|
///
|
||||||
|
/// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
|
||||||
|
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
|
||||||
|
/// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
|
||||||
|
Discriminant(Place),
|
||||||
|
|
||||||
|
/// Yields the length of the place, as a `usize`.
|
||||||
|
///
|
||||||
|
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
|
||||||
|
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
|
||||||
|
/// ill-formed for places of other types.
|
||||||
|
Len(Place),
|
||||||
|
|
||||||
|
/// Creates a reference to the place.
|
||||||
|
Ref(Region, BorrowKind, Place),
|
||||||
|
|
||||||
|
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
|
||||||
|
///
|
||||||
|
/// This is different from a normal transmute because dataflow analysis will treat the box as
|
||||||
|
/// initialized but its content as uninitialized. Like other pointer casts, this in general
|
||||||
|
/// affects alias analysis.
|
||||||
|
ShallowInitBox(Operand, Ty),
|
||||||
|
|
||||||
|
/// Creates a pointer/reference to the given thread local.
|
||||||
|
///
|
||||||
|
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
|
||||||
|
/// `*const T`, and if neither of those apply a `&T`.
|
||||||
|
///
|
||||||
|
/// **Note:** This is a runtime operation that actually executes code and is in this sense more
|
||||||
|
/// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
|
||||||
|
/// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
|
||||||
|
///
|
||||||
|
/// **Needs clarification**: Are there weird additional semantics here related to the runtime
|
||||||
|
/// nature of this operation?
|
||||||
|
ThreadLocalRef(stable_mir::CrateItem),
|
||||||
|
|
||||||
|
/// Exactly like `BinaryOp`, but less operands.
|
||||||
|
///
|
||||||
|
/// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
|
||||||
|
/// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
|
||||||
|
/// return a value with the same type as their operand.
|
||||||
UnaryOp(UnOp, Operand),
|
UnaryOp(UnOp, Operand),
|
||||||
|
|
||||||
|
/// Yields the operand unchanged
|
||||||
|
Use(Operand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -157,8 +244,98 @@ pub struct Place {
|
||||||
pub projection: String,
|
pub projection: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FieldIdx = usize;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SwitchTarget {
|
pub struct SwitchTarget {
|
||||||
pub value: u128,
|
pub value: u128,
|
||||||
pub target: usize,
|
pub target: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum BorrowKind {
|
||||||
|
/// Data must be immutable and is aliasable.
|
||||||
|
Shared,
|
||||||
|
|
||||||
|
/// The immediately borrowed place must be immutable, but projections from
|
||||||
|
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
|
||||||
|
/// conflict with a mutable borrow of `a.b.c`.
|
||||||
|
Shallow,
|
||||||
|
|
||||||
|
/// Data is mutable and not aliasable.
|
||||||
|
Mut {
|
||||||
|
/// `true` if this borrow arose from method-call auto-ref
|
||||||
|
kind: MutBorrowKind,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum MutBorrowKind {
|
||||||
|
Default,
|
||||||
|
TwoPhaseBorrow,
|
||||||
|
ClosureCapture,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Mutability {
|
||||||
|
Not,
|
||||||
|
Mut,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Safety {
|
||||||
|
Unsafe,
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum PointerCoercion {
|
||||||
|
/// Go from a fn-item type to a fn-pointer type.
|
||||||
|
ReifyFnPointer,
|
||||||
|
|
||||||
|
/// Go from a safe fn pointer to an unsafe fn pointer.
|
||||||
|
UnsafeFnPointer,
|
||||||
|
|
||||||
|
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
|
||||||
|
/// It cannot convert a closure that requires unsafe.
|
||||||
|
ClosureFnPointer(Safety),
|
||||||
|
|
||||||
|
/// Go from a mut raw pointer to a const raw pointer.
|
||||||
|
MutToConstPointer,
|
||||||
|
|
||||||
|
/// Go from `*const [T; N]` to `*const T`
|
||||||
|
ArrayToPointer,
|
||||||
|
|
||||||
|
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
|
||||||
|
/// `&[T]`. Note that the source could be a thin or fat pointer.
|
||||||
|
/// This will do things like convert thin pointers to fat
|
||||||
|
/// pointers, or convert structs containing thin pointers to
|
||||||
|
/// structs containing fat pointers, or convert between fat
|
||||||
|
/// pointers.
|
||||||
|
Unsize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum CastKind {
|
||||||
|
PointerExposeAddress,
|
||||||
|
PointerFromExposedAddress,
|
||||||
|
PointerCoercion(PointerCoercion),
|
||||||
|
DynStar,
|
||||||
|
IntToInt,
|
||||||
|
FloatToInt,
|
||||||
|
FloatToFloat,
|
||||||
|
IntToFloat,
|
||||||
|
PtrToPtr,
|
||||||
|
FnPtrToPtr,
|
||||||
|
Transmute,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum NullOp {
|
||||||
|
/// Returns the size of a value of that type.
|
||||||
|
SizeOf,
|
||||||
|
/// Returns the minimum alignment of a type.
|
||||||
|
AlignOf,
|
||||||
|
/// Returns the offset of a field.
|
||||||
|
OffsetOf(Vec<FieldIdx>),
|
||||||
|
}
|
||||||
|
|
|
@ -1152,8 +1152,10 @@ symbols! {
|
||||||
profiler_runtime,
|
profiler_runtime,
|
||||||
ptr,
|
ptr,
|
||||||
ptr_cast_mut,
|
ptr_cast_mut,
|
||||||
|
ptr_const_is_null,
|
||||||
ptr_from_ref,
|
ptr_from_ref,
|
||||||
ptr_guaranteed_cmp,
|
ptr_guaranteed_cmp,
|
||||||
|
ptr_is_null,
|
||||||
ptr_mask,
|
ptr_mask,
|
||||||
ptr_null,
|
ptr_null,
|
||||||
ptr_null_mut,
|
ptr_null_mut,
|
||||||
|
|
|
@ -1640,6 +1640,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
};
|
};
|
||||||
|
// FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice
|
||||||
|
// to deeply normalize this type.
|
||||||
let normalized_term =
|
let normalized_term =
|
||||||
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
|
ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
|
||||||
|
|
||||||
|
|
|
@ -131,8 +131,6 @@ enum ProjectionCandidate<'tcx> {
|
||||||
|
|
||||||
/// From an "impl" (or a "pseudo-impl" returned by select)
|
/// From an "impl" (or a "pseudo-impl" returned by select)
|
||||||
Select(Selection<'tcx>),
|
Select(Selection<'tcx>),
|
||||||
|
|
||||||
ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProjectionCandidateSet<'tcx> {
|
enum ProjectionCandidateSet<'tcx> {
|
||||||
|
@ -1472,8 +1470,6 @@ fn project<'cx, 'tcx>(
|
||||||
|
|
||||||
let mut candidates = ProjectionCandidateSet::None;
|
let mut candidates = ProjectionCandidateSet::None;
|
||||||
|
|
||||||
assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates);
|
|
||||||
|
|
||||||
// Make sure that the following procedures are kept in order. ParamEnv
|
// Make sure that the following procedures are kept in order. ParamEnv
|
||||||
// needs to be first because it has highest priority, and Select checks
|
// needs to be first because it has highest priority, and Select checks
|
||||||
// the return value of push_candidate which assumes it's ran at last.
|
// the return value of push_candidate which assumes it's ran at last.
|
||||||
|
@ -1499,7 +1495,7 @@ fn project<'cx, 'tcx>(
|
||||||
ProjectionCandidateSet::None => {
|
ProjectionCandidateSet::None => {
|
||||||
let tcx = selcx.tcx();
|
let tcx = selcx.tcx();
|
||||||
let term = match tcx.def_kind(obligation.predicate.def_id) {
|
let term = match tcx.def_kind(obligation.predicate.def_id) {
|
||||||
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => Ty::new_projection(
|
DefKind::AssocTy => Ty::new_projection(
|
||||||
tcx,
|
tcx,
|
||||||
obligation.predicate.def_id,
|
obligation.predicate.def_id,
|
||||||
obligation.predicate.substs,
|
obligation.predicate.substs,
|
||||||
|
@ -1530,47 +1526,6 @@ fn project<'cx, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the
|
|
||||||
/// corresponding trait ref. If this yields an `impl`, then we're able to project
|
|
||||||
/// to a concrete type, since we have an `impl`'s method to provide the RPITIT.
|
|
||||||
fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
|
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
|
||||||
candidate_set: &mut ProjectionCandidateSet<'tcx>,
|
|
||||||
) {
|
|
||||||
let tcx = selcx.tcx();
|
|
||||||
if tcx.def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
|
|
||||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
|
|
||||||
|
|
||||||
let trait_def_id = tcx.parent(trait_fn_def_id);
|
|
||||||
let trait_substs =
|
|
||||||
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
|
|
||||||
let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs);
|
|
||||||
|
|
||||||
let _ = selcx.infcx.commit_if_ok(|_| {
|
|
||||||
match selcx.select(&obligation.with(tcx, trait_predicate)) {
|
|
||||||
Ok(Some(super::ImplSource::UserDefined(data))) => {
|
|
||||||
candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
candidate_set.mark_ambiguous();
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
Ok(Some(_)) => {
|
|
||||||
// Don't know enough about the impl to provide a useful signature
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
debug!(error = ?e, "selection error");
|
|
||||||
candidate_set.mark_error(e);
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The first thing we have to do is scan through the parameter
|
/// The first thing we have to do is scan through the parameter
|
||||||
/// environment to see whether there are any projection predicates
|
/// environment to see whether there are any projection predicates
|
||||||
/// there that can answer this question.
|
/// there that can answer this question.
|
||||||
|
@ -1739,11 +1694,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
candidate_set: &mut ProjectionCandidateSet<'tcx>,
|
candidate_set: &mut ProjectionCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
// Can't assemble candidate from impl for RPITIT
|
|
||||||
if selcx.tcx().def_kind(obligation.predicate.def_id) == DefKind::ImplTraitPlaceholder {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
// If we are resolving `<T as TraitRef<...>>::Item == Type`,
|
||||||
// start out by selecting the predicate `T as TraitRef<...>`:
|
// start out by selecting the predicate `T as TraitRef<...>`:
|
||||||
let trait_ref = obligation.predicate.trait_ref(selcx.tcx());
|
let trait_ref = obligation.predicate.trait_ref(selcx.tcx());
|
||||||
|
@ -2012,9 +1962,6 @@ fn confirm_candidate<'cx, 'tcx>(
|
||||||
ProjectionCandidate::Select(impl_source) => {
|
ProjectionCandidate::Select(impl_source) => {
|
||||||
confirm_select_candidate(selcx, obligation, impl_source)
|
confirm_select_candidate(selcx, obligation, impl_source)
|
||||||
}
|
}
|
||||||
ProjectionCandidate::ImplTraitInTrait(data) => {
|
|
||||||
confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// When checking for cycle during evaluation, we compare predicates with
|
// When checking for cycle during evaluation, we compare predicates with
|
||||||
|
@ -2240,8 +2187,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
nested: Vec<PredicateObligation<'tcx>>,
|
nested: Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
let ty::Closure(_, substs) =
|
let ty::Closure(_, substs) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
|
||||||
selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
|
|
||||||
else {
|
else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -2419,103 +2365,6 @@ fn confirm_impl_candidate<'cx, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_impl_trait_in_trait_candidate<'tcx>(
|
|
||||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
|
||||||
data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
|
|
||||||
) -> Progress<'tcx> {
|
|
||||||
let tcx = selcx.tcx();
|
|
||||||
let mut obligations = data.nested;
|
|
||||||
|
|
||||||
let trait_fn_def_id = tcx.impl_trait_in_trait_parent_fn(obligation.predicate.def_id);
|
|
||||||
let leaf_def = match specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) {
|
|
||||||
Ok(assoc_ty) => assoc_ty,
|
|
||||||
Err(guar) => return Progress::error(tcx, guar),
|
|
||||||
};
|
|
||||||
// We don't support specialization for RPITITs anyways... yet.
|
|
||||||
// Also don't try to project to an RPITIT that has no value
|
|
||||||
if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() {
|
|
||||||
return Progress { term: Ty::new_misc_error(tcx).into(), obligations };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the default `impl Trait` for the trait, e.g., for a default trait body
|
|
||||||
if leaf_def.item.container == ty::AssocItemContainer::TraitContainer {
|
|
||||||
return Progress {
|
|
||||||
term: Ty::new_opaque(tcx, obligation.predicate.def_id, obligation.predicate.substs)
|
|
||||||
.into(),
|
|
||||||
obligations,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
|
|
||||||
// since `data.substs` are the impl substs.
|
|
||||||
let impl_fn_substs =
|
|
||||||
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
|
|
||||||
let impl_fn_substs = translate_substs(
|
|
||||||
selcx.infcx,
|
|
||||||
obligation.param_env,
|
|
||||||
data.impl_def_id,
|
|
||||||
impl_fn_substs,
|
|
||||||
leaf_def.defining_node,
|
|
||||||
);
|
|
||||||
|
|
||||||
if !check_substs_compatible(tcx, leaf_def.item, impl_fn_substs) {
|
|
||||||
let err = Ty::new_error_with_message(
|
|
||||||
tcx,
|
|
||||||
obligation.cause.span,
|
|
||||||
"impl method and trait method have different parameters",
|
|
||||||
);
|
|
||||||
return Progress { term: err.into(), obligations };
|
|
||||||
}
|
|
||||||
|
|
||||||
let impl_fn_def_id = leaf_def.item.def_id;
|
|
||||||
|
|
||||||
let cause = ObligationCause::new(
|
|
||||||
obligation.cause.span,
|
|
||||||
obligation.cause.body_id,
|
|
||||||
super::ItemObligation(impl_fn_def_id),
|
|
||||||
);
|
|
||||||
let predicates = normalize_with_depth_to(
|
|
||||||
selcx,
|
|
||||||
obligation.param_env,
|
|
||||||
cause.clone(),
|
|
||||||
obligation.recursion_depth + 1,
|
|
||||||
tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
|
|
||||||
&mut obligations,
|
|
||||||
);
|
|
||||||
obligations.extend(predicates.into_iter().map(|(pred, span)| {
|
|
||||||
Obligation::with_depth(
|
|
||||||
tcx,
|
|
||||||
ObligationCause::new(
|
|
||||||
obligation.cause.span,
|
|
||||||
obligation.cause.body_id,
|
|
||||||
if span.is_dummy() {
|
|
||||||
super::ItemObligation(impl_fn_def_id)
|
|
||||||
} else {
|
|
||||||
super::BindingObligation(impl_fn_def_id, span)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
obligation.recursion_depth + 1,
|
|
||||||
obligation.param_env,
|
|
||||||
pred,
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
|
|
||||||
let ty = normalize_with_depth_to(
|
|
||||||
selcx,
|
|
||||||
obligation.param_env,
|
|
||||||
cause.clone(),
|
|
||||||
obligation.recursion_depth + 1,
|
|
||||||
tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else(
|
|
||||||
|guar| Ty::new_error(tcx, guar),
|
|
||||||
|tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs),
|
|
||||||
),
|
|
||||||
&mut obligations,
|
|
||||||
);
|
|
||||||
|
|
||||||
Progress { term: ty.into(), obligations }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get obligations corresponding to the predicates from the where-clause of the
|
// Get obligations corresponding to the predicates from the where-clause of the
|
||||||
// associated type itself.
|
// associated type itself.
|
||||||
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
fn assoc_ty_own_obligations<'cx, 'tcx>(
|
||||||
|
|
|
@ -24,70 +24,54 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
|
||||||
let item = tcx.hir().expect_item(def_id);
|
let item = tcx.hir().expect_item(def_id);
|
||||||
match item.kind {
|
match item.kind {
|
||||||
hir::ItemKind::Trait(.., ref trait_item_refs) => {
|
hir::ItemKind::Trait(.., ref trait_item_refs) => {
|
||||||
if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
// We collect RPITITs for each trait method's return type and create a
|
||||||
// We collect RPITITs for each trait method's return type and create a
|
// corresponding associated item using associated_types_for_impl_traits_in_associated_fn
|
||||||
// corresponding associated item using associated_types_for_impl_traits_in_associated_fn
|
// query.
|
||||||
// query.
|
tcx.arena.alloc_from_iter(
|
||||||
tcx.arena.alloc_from_iter(
|
trait_item_refs
|
||||||
trait_item_refs
|
.iter()
|
||||||
.iter()
|
.map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
|
||||||
.map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
|
.chain(
|
||||||
.chain(
|
trait_item_refs
|
||||||
trait_item_refs
|
.iter()
|
||||||
.iter()
|
.filter(|trait_item_ref| {
|
||||||
.filter(|trait_item_ref| {
|
matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. })
|
||||||
matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. })
|
})
|
||||||
})
|
.flat_map(|trait_item_ref| {
|
||||||
.flat_map(|trait_item_ref| {
|
let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id();
|
||||||
let trait_fn_def_id =
|
tcx.associated_types_for_impl_traits_in_associated_fn(
|
||||||
trait_item_ref.id.owner_id.def_id.to_def_id();
|
trait_fn_def_id,
|
||||||
tcx.associated_types_for_impl_traits_in_associated_fn(
|
)
|
||||||
trait_fn_def_id,
|
})
|
||||||
)
|
.map(|def_id| *def_id),
|
||||||
})
|
),
|
||||||
.map(|def_id| *def_id),
|
)
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
tcx.arena.alloc_from_iter(
|
|
||||||
trait_item_refs
|
|
||||||
.iter()
|
|
||||||
.map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
hir::ItemKind::Impl(ref impl_) => {
|
hir::ItemKind::Impl(ref impl_) => {
|
||||||
if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
// We collect RPITITs for each trait method's return type, on the impl side too and
|
||||||
// We collect RPITITs for each trait method's return type, on the impl side too and
|
// create a corresponding associated item using
|
||||||
// create a corresponding associated item using
|
// associated_types_for_impl_traits_in_associated_fn query.
|
||||||
// associated_types_for_impl_traits_in_associated_fn query.
|
tcx.arena.alloc_from_iter(
|
||||||
tcx.arena.alloc_from_iter(
|
impl_
|
||||||
impl_
|
.items
|
||||||
.items
|
.iter()
|
||||||
.iter()
|
.map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
|
||||||
.map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
|
.chain(impl_.of_trait.iter().flat_map(|_| {
|
||||||
.chain(impl_.of_trait.iter().flat_map(|_| {
|
impl_
|
||||||
impl_
|
.items
|
||||||
.items
|
.iter()
|
||||||
.iter()
|
.filter(|impl_item_ref| {
|
||||||
.filter(|impl_item_ref| {
|
matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. })
|
||||||
matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. })
|
})
|
||||||
})
|
.flat_map(|impl_item_ref| {
|
||||||
.flat_map(|impl_item_ref| {
|
let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id();
|
||||||
let impl_fn_def_id =
|
tcx.associated_types_for_impl_traits_in_associated_fn(
|
||||||
impl_item_ref.id.owner_id.def_id.to_def_id();
|
impl_fn_def_id,
|
||||||
tcx.associated_types_for_impl_traits_in_associated_fn(
|
)
|
||||||
impl_fn_def_id,
|
})
|
||||||
)
|
.map(|def_id| *def_id)
|
||||||
})
|
})),
|
||||||
.map(|def_id| *def_id)
|
)
|
||||||
})),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
tcx.arena.alloc_from_iter(
|
|
||||||
impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
|
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,6 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::AnonConst
|
| DefKind::AnonConst
|
||||||
| DefKind::InlineConst
|
| DefKind::InlineConst
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::LifetimeParam
|
| DefKind::LifetimeParam
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
|
|
|
@ -318,7 +318,6 @@ fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [
|
||||||
| DefKind::ExternCrate
|
| DefKind::ExternCrate
|
||||||
| DefKind::Use
|
| DefKind::Use
|
||||||
| DefKind::ForeignMod
|
| DefKind::ForeignMod
|
||||||
| DefKind::ImplTraitPlaceholder
|
|
||||||
| DefKind::Field
|
| DefKind::Field
|
||||||
| DefKind::LifetimeParam
|
| DefKind::LifetimeParam
|
||||||
| DefKind::GlobalAsm
|
| DefKind::GlobalAsm
|
||||||
|
|
|
@ -282,11 +282,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
|
||||||
// If we're lowering to associated item, install the opaque type which is just
|
// If we're lowering to associated item, install the opaque type which is just
|
||||||
// the `type_of` of the trait's associated item. If we're using the old lowering
|
// the `type_of` of the trait's associated item. If we're using the old lowering
|
||||||
// strategy, then just reinterpret the associated type like an opaque :^)
|
// strategy, then just reinterpret the associated type like an opaque :^)
|
||||||
let default_ty = if self.tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
let default_ty = self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs);
|
||||||
self.tcx.type_of(shifted_alias_ty.def_id).subst(self.tcx, shifted_alias_ty.substs)
|
|
||||||
} else {
|
|
||||||
Ty::new_alias(self.tcx,ty::Opaque, shifted_alias_ty)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.predicates.push(
|
self.predicates.push(
|
||||||
ty::Binder::bind_with_vars(
|
ty::Binder::bind_with_vars(
|
||||||
|
@ -408,9 +404,7 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32
|
||||||
};
|
};
|
||||||
|
|
||||||
// The last field of the structure has to exist and contain type/const parameters.
|
// The last field of the structure has to exist and contain type/const parameters.
|
||||||
let Some((tail_field, prefix_fields)) =
|
let Some((tail_field, prefix_fields)) = def.non_enum_variant().fields.raw.split_last() else {
|
||||||
def.non_enum_variant().fields.raw.split_last() else
|
|
||||||
{
|
|
||||||
return BitSet::new_empty(num_params);
|
return BitSet::new_empty(num_params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ mod macros;
|
||||||
mod structural_impls;
|
mod structural_impls;
|
||||||
|
|
||||||
pub use codec::*;
|
pub use codec::*;
|
||||||
|
pub use structural_impls::{DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
pub use sty::*;
|
pub use sty::*;
|
||||||
pub use ty_info::*;
|
pub use ty_info::*;
|
||||||
|
|
||||||
|
@ -39,41 +40,41 @@ pub trait HashStableContext {}
|
||||||
|
|
||||||
pub trait Interner: Sized {
|
pub trait Interner: Sized {
|
||||||
type AdtDef: Clone + Debug + Hash + Ord;
|
type AdtDef: Clone + Debug + Hash + Ord;
|
||||||
type SubstsRef: Clone + Debug + Hash + Ord;
|
type SubstsRef: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type DefId: Clone + Debug + Hash + Ord;
|
type DefId: Clone + Debug + Hash + Ord;
|
||||||
type Binder<T>;
|
type Binder<T>;
|
||||||
type Ty: Clone + Debug + Hash + Ord;
|
type Ty: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type Const: Clone + Debug + Hash + Ord;
|
type Const: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type Region: Clone + Debug + Hash + Ord;
|
type Region: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type Predicate;
|
type Predicate;
|
||||||
type TypeAndMut: Clone + Debug + Hash + Ord;
|
type TypeAndMut: Clone + Debug + Hash + Ord;
|
||||||
type Mutability: Clone + Debug + Hash + Ord;
|
type Mutability: Clone + Debug + Hash + Ord;
|
||||||
type Movability: Clone + Debug + Hash + Ord;
|
type Movability: Clone + Debug + Hash + Ord;
|
||||||
type PolyFnSig: Clone + Debug + Hash + Ord;
|
type PolyFnSig: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type ListBinderExistentialPredicate: Clone + Debug + Hash + Ord;
|
type ListBinderExistentialPredicate: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type BinderListTy: Clone + Debug + Hash + Ord;
|
type BinderListTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type ListTy: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
|
type ListTy: Clone + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
|
||||||
type AliasTy: Clone + Debug + Hash + Ord;
|
type AliasTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type ParamTy: Clone + Debug + Hash + Ord;
|
type ParamTy: Clone + Debug + Hash + Ord;
|
||||||
type BoundTy: Clone + Debug + Hash + Ord;
|
type BoundTy: Clone + Debug + Hash + Ord;
|
||||||
type PlaceholderType: Clone + Debug + Hash + Ord;
|
type PlaceholderType: Clone + Debug + Hash + Ord;
|
||||||
|
type InferTy: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
type ErrorGuaranteed: Clone + Debug + Hash + Ord;
|
||||||
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
|
||||||
type AllocId: Clone + Debug + Hash + Ord;
|
type AllocId: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
type InferConst: Clone + Debug + Hash + Ord;
|
type InferConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type AliasConst: Clone + Debug + Hash + Ord;
|
type AliasConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
type PlaceholderConst: Clone + Debug + Hash + Ord;
|
||||||
type ParamConst: Clone + Debug + Hash + Ord;
|
type ParamConst: Clone + Debug + Hash + Ord;
|
||||||
type BoundConst: Clone + Debug + Hash + Ord;
|
type BoundConst: Clone + Debug + Hash + Ord;
|
||||||
type InferTy: Clone + Debug + Hash + Ord;
|
|
||||||
type ValueConst: Clone + Debug + Hash + Ord;
|
type ValueConst: Clone + Debug + Hash + Ord;
|
||||||
type ExprConst: Clone + Debug + Hash + Ord;
|
type ExprConst: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
|
|
||||||
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
type EarlyBoundRegion: Clone + Debug + Hash + Ord;
|
||||||
type BoundRegion: Clone + Debug + Hash + Ord;
|
type BoundRegion: Clone + Debug + Hash + Ord;
|
||||||
type FreeRegion: Clone + Debug + Hash + Ord;
|
type FreeRegion: Clone + Debug + Hash + Ord;
|
||||||
type RegionVid: Clone + Debug + Hash + Ord;
|
type RegionVid: Clone + DebugWithInfcx<Self> + Hash + Ord;
|
||||||
type PlaceholderRegion: Clone + Debug + Hash + Ord;
|
type PlaceholderRegion: Clone + Debug + Hash + Ord;
|
||||||
|
|
||||||
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability);
|
fn ty_and_mut_to_parts(ty_and_mut: Self::TypeAndMut) -> (Self::Ty, Self::Mutability);
|
||||||
|
@ -775,20 +776,6 @@ impl fmt::Debug for FloatVid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for InferTy {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use InferTy::*;
|
|
||||||
match *self {
|
|
||||||
TyVar(ref v) => v.fmt(f),
|
|
||||||
IntVar(ref v) => v.fmt(f),
|
|
||||||
FloatVar(ref v) => v.fmt(f),
|
|
||||||
FreshTy(v) => write!(f, "FreshTy({v:?})"),
|
|
||||||
FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
|
|
||||||
FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Variance {
|
impl fmt::Debug for Variance {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.write_str(match *self {
|
f.write_str(match *self {
|
||||||
|
|
|
@ -4,12 +4,13 @@
|
||||||
|
|
||||||
use crate::fold::{FallibleTypeFolder, TypeFoldable};
|
use crate::fold::{FallibleTypeFolder, TypeFoldable};
|
||||||
use crate::visit::{TypeVisitable, TypeVisitor};
|
use crate::visit::{TypeVisitable, TypeVisitor};
|
||||||
use crate::{ConstKind, FloatTy, IntTy, Interner, UintTy};
|
use crate::{ConstKind, FloatTy, InferTy, IntTy, Interner, UintTy, UniverseIndex};
|
||||||
use rustc_data_structures::functor::IdFunctor;
|
use rustc_data_structures::functor::IdFunctor;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_index::{Idx, IndexVec};
|
use rustc_index::{Idx, IndexVec};
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -165,6 +166,116 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// Debug impls
|
||||||
|
|
||||||
|
pub trait InferCtxtLike<I: Interner> {
|
||||||
|
fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>;
|
||||||
|
fn universe_of_lt(&self, lt: I::RegionVid) -> Option<UniverseIndex>;
|
||||||
|
fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible {
|
||||||
|
fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
fn universe_of_lt(&self, _lt: <I as Interner>::RegionVid) -> Option<UniverseIndex> {
|
||||||
|
match *self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
<T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
match f.alternate() {
|
||||||
|
true => {
|
||||||
|
write!(f, "[\n")?;
|
||||||
|
for element in this.data.iter() {
|
||||||
|
write!(f, "{:?},\n", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
write!(f, "[")?;
|
||||||
|
if this.data.len() > 0 {
|
||||||
|
for element in &this.data[..(this.data.len() - 1)] {
|
||||||
|
write!(f, "{:?}, ", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
if let Some(element) = this.data.last() {
|
||||||
|
write!(f, "{:?}", &this.wrap(element))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> {
|
||||||
|
pub data: T,
|
||||||
|
pub infcx: Option<&'a InfCtx>,
|
||||||
|
_interner: PhantomData<I>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {}
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> {
|
||||||
|
pub fn new_no_ctx(data: T) -> Self {
|
||||||
|
Self { data, infcx: None, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> {
|
||||||
|
pub fn new(data: T, infcx: &'a InfCtx) -> Self {
|
||||||
|
Self { data, infcx: Some(infcx), _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
||||||
|
OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> {
|
||||||
|
OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> {
|
||||||
|
OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug
|
||||||
|
for OptWithInfcx<'_, I, InfCtx, T>
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
DebugWithInfcx::fmt(self.as_ref(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for IntTy {
|
impl fmt::Debug for IntTy {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.name_str())
|
write!(f, "{}", self.name_str())
|
||||||
|
@ -183,20 +294,60 @@ impl fmt::Debug for FloatTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
impl fmt::Debug for InferTy {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use ConstKind::*;
|
use InferTy::*;
|
||||||
match self {
|
match *self {
|
||||||
Param(param) => write!(f, "{param:?}"),
|
TyVar(ref v) => v.fmt(f),
|
||||||
Infer(var) => write!(f, "{var:?}"),
|
IntVar(ref v) => v.fmt(f),
|
||||||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
|
FloatVar(ref v) => v.fmt(f),
|
||||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
FreshTy(v) => write!(f, "FreshTy({v:?})"),
|
||||||
Unevaluated(uv) => {
|
FreshIntTy(v) => write!(f, "FreshIntTy({v:?})"),
|
||||||
write!(f, "{uv:?}")
|
FreshFloatTy(v) => write!(f, "FreshFloatTy({v:?})"),
|
||||||
}
|
}
|
||||||
Value(valtree) => write!(f, "{valtree:?}"),
|
}
|
||||||
Error(_) => write!(f, "{{const error}}"),
|
}
|
||||||
Expr(expr) => write!(f, "{expr:?}"),
|
impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
use InferTy::*;
|
||||||
|
match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) {
|
||||||
|
None => write!(f, "{:?}", this.data),
|
||||||
|
Some(universe) => match *this.data {
|
||||||
|
TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),
|
||||||
|
IntVar(_) | FloatVar(_) | FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_) => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Interner> fmt::Debug for ConstKind<I> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
|
||||||
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
use ConstKind::*;
|
||||||
|
|
||||||
|
match this.data {
|
||||||
|
Param(param) => write!(f, "{param:?}"),
|
||||||
|
Infer(var) => write!(f, "{:?}", &this.wrap(var)),
|
||||||
|
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var.clone()),
|
||||||
|
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||||
|
Unevaluated(uv) => {
|
||||||
|
write!(f, "{:?}", &this.wrap(uv))
|
||||||
|
}
|
||||||
|
Value(valtree) => write!(f, "{valtree:?}"),
|
||||||
|
Error(_) => write!(f, "{{const error}}"),
|
||||||
|
Expr(expr) => write!(f, "{:?}", &this.wrap(expr)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::{fmt, hash};
|
use std::{fmt, hash};
|
||||||
|
|
||||||
use crate::DebruijnIndex;
|
|
||||||
use crate::FloatTy;
|
use crate::FloatTy;
|
||||||
use crate::HashStableContext;
|
use crate::HashStableContext;
|
||||||
use crate::IntTy;
|
use crate::IntTy;
|
||||||
|
@ -11,6 +10,7 @@ use crate::Interner;
|
||||||
use crate::TyDecoder;
|
use crate::TyDecoder;
|
||||||
use crate::TyEncoder;
|
use crate::TyEncoder;
|
||||||
use crate::UintTy;
|
use crate::UintTy;
|
||||||
|
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
|
|
||||||
use self::RegionKind::*;
|
use self::RegionKind::*;
|
||||||
use self::TyKind::*;
|
use self::TyKind::*;
|
||||||
|
@ -503,42 +503,48 @@ impl<I: Interner> hash::Hash for TyKind<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Debug`
|
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
|
||||||
impl<I: Interner> fmt::Debug for TyKind<I> {
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
match self {
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> fmt::Result {
|
||||||
|
match this.data {
|
||||||
Bool => write!(f, "bool"),
|
Bool => write!(f, "bool"),
|
||||||
Char => write!(f, "char"),
|
Char => write!(f, "char"),
|
||||||
Int(i) => write!(f, "{i:?}"),
|
Int(i) => write!(f, "{i:?}"),
|
||||||
Uint(u) => write!(f, "{u:?}"),
|
Uint(u) => write!(f, "{u:?}"),
|
||||||
Float(float) => write!(f, "{float:?}"),
|
Float(float) => write!(f, "{float:?}"),
|
||||||
Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, s),
|
Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, &this.wrap(s)),
|
||||||
Foreign(d) => f.debug_tuple_field1_finish("Foreign", d),
|
Foreign(d) => f.debug_tuple_field1_finish("Foreign", d),
|
||||||
Str => write!(f, "str"),
|
Str => write!(f, "str"),
|
||||||
Array(t, c) => write!(f, "[{t:?}; {c:?}]"),
|
Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
|
||||||
Slice(t) => write!(f, "[{t:?}]"),
|
Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
|
||||||
RawPtr(p) => {
|
RawPtr(p) => {
|
||||||
let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone());
|
let (ty, mutbl) = I::ty_and_mut_to_parts(p.clone());
|
||||||
match I::mutability_is_mut(mutbl) {
|
match I::mutability_is_mut(mutbl) {
|
||||||
true => write!(f, "*mut "),
|
true => write!(f, "*mut "),
|
||||||
false => write!(f, "*const "),
|
false => write!(f, "*const "),
|
||||||
}?;
|
}?;
|
||||||
write!(f, "{ty:?}")
|
write!(f, "{:?}", &this.wrap(ty))
|
||||||
}
|
}
|
||||||
Ref(r, t, m) => match I::mutability_is_mut(m.clone()) {
|
Ref(r, t, m) => match I::mutability_is_mut(m.clone()) {
|
||||||
true => write!(f, "&{r:?} mut {t:?}"),
|
true => write!(f, "&{:?} mut {:?}", &this.wrap(r), &this.wrap(t)),
|
||||||
false => write!(f, "&{r:?} {t:?}"),
|
false => write!(f, "&{:?} {:?}", &this.wrap(r), &this.wrap(t)),
|
||||||
},
|
},
|
||||||
FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, s),
|
FnDef(d, s) => f.debug_tuple_field2_finish("FnDef", d, &this.wrap(s)),
|
||||||
FnPtr(s) => write!(f, "{s:?}"),
|
FnPtr(s) => write!(f, "{:?}", &this.wrap(s)),
|
||||||
Dynamic(p, r, repr) => match repr {
|
Dynamic(p, r, repr) => match repr {
|
||||||
DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
|
DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &this.wrap(p), &this.wrap(r)),
|
||||||
DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"),
|
DynKind::DynStar => {
|
||||||
|
write!(f, "dyn* {:?} + {:?}", &this.wrap(p), &this.wrap(r))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, s),
|
Closure(d, s) => f.debug_tuple_field2_finish("Closure", d, &this.wrap(s)),
|
||||||
Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, s, m),
|
Generator(d, s, m) => f.debug_tuple_field3_finish("Generator", d, &this.wrap(s), m),
|
||||||
GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", g),
|
GeneratorWitness(g) => f.debug_tuple_field1_finish("GeneratorWitness", &this.wrap(g)),
|
||||||
GeneratorWitnessMIR(d, s) => f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, s),
|
GeneratorWitnessMIR(d, s) => {
|
||||||
|
f.debug_tuple_field2_finish("GeneratorWitnessMIR", d, &this.wrap(s))
|
||||||
|
}
|
||||||
Never => write!(f, "!"),
|
Never => write!(f, "!"),
|
||||||
Tuple(t) => {
|
Tuple(t) => {
|
||||||
let mut iter = t.clone().into_iter();
|
let mut iter = t.clone().into_iter();
|
||||||
|
@ -547,28 +553,34 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||||
|
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
None => return write!(f, ")"),
|
None => return write!(f, ")"),
|
||||||
Some(ty) => write!(f, "{ty:?}")?,
|
Some(ty) => write!(f, "{:?}", &this.wrap(ty))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
None => return write!(f, ",)"),
|
None => return write!(f, ",)"),
|
||||||
Some(ty) => write!(f, "{ty:?})")?,
|
Some(ty) => write!(f, "{:?})", &this.wrap(ty))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
for ty in iter {
|
for ty in iter {
|
||||||
write!(f, ", {ty:?}")?;
|
write!(f, ", {:?}", &this.wrap(ty))?;
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, a),
|
Alias(i, a) => f.debug_tuple_field2_finish("Alias", i, &this.wrap(a)),
|
||||||
Param(p) => write!(f, "{p:?}"),
|
Param(p) => write!(f, "{p:?}"),
|
||||||
Bound(d, b) => crate::debug_bound_var(f, *d, b),
|
Bound(d, b) => crate::debug_bound_var(f, *d, b),
|
||||||
Placeholder(p) => write!(f, "{p:?}"),
|
Placeholder(p) => write!(f, "{p:?}"),
|
||||||
Infer(t) => write!(f, "{t:?}"),
|
Infer(t) => write!(f, "{:?}", this.wrap(t)),
|
||||||
TyKind::Error(_) => write!(f, "{{type error}}"),
|
TyKind::Error(_) => write!(f, "{{type error}}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// This is manually implemented because a derive would require `I: Debug`
|
||||||
|
impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Encodable`
|
// This is manually implemented because a derive would require `I: Encodable`
|
||||||
impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
|
impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
|
||||||
|
@ -1356,21 +1368,23 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Debug`
|
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
|
||||||
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
fn fmt<InfCtx: InferCtxtLike<I>>(
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
this: OptWithInfcx<'_, I, InfCtx, &Self>,
|
||||||
match self {
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
|
) -> core::fmt::Result {
|
||||||
|
match this.data {
|
||||||
ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
|
ReEarlyBound(data) => write!(f, "ReEarlyBound({data:?})"),
|
||||||
|
|
||||||
ReLateBound(binder_id, bound_region) => {
|
ReLateBound(binder_id, bound_region) => {
|
||||||
write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
|
write!(f, "ReLateBound({binder_id:?}, {bound_region:?})")
|
||||||
}
|
}
|
||||||
|
|
||||||
ReFree(fr) => fr.fmt(f),
|
ReFree(fr) => write!(f, "{fr:?}"),
|
||||||
|
|
||||||
ReStatic => f.write_str("ReStatic"),
|
ReStatic => f.write_str("ReStatic"),
|
||||||
|
|
||||||
ReVar(vid) => vid.fmt(f),
|
ReVar(vid) => write!(f, "{:?}", &this.wrap(vid)),
|
||||||
|
|
||||||
RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
|
RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
|
||||||
|
|
||||||
|
@ -1380,6 +1394,11 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
OptWithInfcx::new_no_ctx(self).fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is manually implemented because a derive would require `I: Encodable`
|
// This is manually implemented because a derive would require `I: Encodable`
|
||||||
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
|
impl<I: Interner, E: TyEncoder> Encodable<E> for RegionKind<I>
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::marker::ConstParamTy;
|
||||||
#[lang = "transmute_trait"]
|
#[lang = "transmute_trait"]
|
||||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
|
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl(implement_via_object = false))]
|
||||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
|
#[cfg_attr(bootstrap, rustc_deny_explicit_impl)]
|
||||||
|
#[rustc_coinductive]
|
||||||
pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
|
pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }>
|
||||||
where
|
where
|
||||||
Src: ?Sized,
|
Src: ?Sized,
|
||||||
|
|
|
@ -30,6 +30,7 @@ impl<T: ?Sized> *const T {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||||
|
#[rustc_diagnostic_item = "ptr_const_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -29,6 +29,7 @@ impl<T: ?Sized> *mut T {
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
#[rustc_const_unstable(feature = "const_ptr_is_null", issue = "74939")]
|
||||||
|
#[rustc_diagnostic_item = "ptr_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -16,6 +16,7 @@ use crate::fmt;
|
||||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||||
use crate::path::{Path, PathBuf};
|
use crate::path::{Path, PathBuf};
|
||||||
use crate::sealed::Sealed;
|
use crate::sealed::Sealed;
|
||||||
|
use crate::sync::Arc;
|
||||||
use crate::sys::fs as fs_imp;
|
use crate::sys::fs as fs_imp;
|
||||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||||
use crate::time::SystemTime;
|
use crate::time::SystemTime;
|
||||||
|
@ -742,78 +743,20 @@ fn buffer_capacity_required(mut file: &File) -> Option<usize> {
|
||||||
Some(size.saturating_sub(pos) as usize)
|
Some(size.saturating_sub(pos) as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
impl Read for File {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
self.inner.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
|
||||||
self.inner.read_vectored(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
|
||||||
self.inner.read_buf(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_read_vectored(&self) -> bool {
|
|
||||||
self.inner.is_read_vectored()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserves space in the buffer based on the file size when available.
|
|
||||||
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
||||||
let size = buffer_capacity_required(self);
|
|
||||||
buf.reserve(size.unwrap_or(0));
|
|
||||||
io::default_read_to_end(self, buf, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reserves space in the buffer based on the file size when available.
|
|
||||||
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
|
||||||
let size = buffer_capacity_required(self);
|
|
||||||
buf.reserve(size.unwrap_or(0));
|
|
||||||
io::default_read_to_string(self, buf, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
impl Write for File {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
self.inner.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
|
||||||
self.inner.write_vectored(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_write_vectored(&self) -> bool {
|
|
||||||
self.inner.is_write_vectored()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
self.inner.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
|
||||||
impl Seek for File {
|
|
||||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
|
||||||
self.inner.seek(pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl Read for &File {
|
impl Read for &File {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
self.inner.read(buf)
|
self.inner.read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
|
||||||
self.inner.read_buf(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||||
self.inner.read_vectored(bufs)
|
self.inner.read_vectored(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||||
|
self.inner.read_buf(cursor)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_read_vectored(&self) -> bool {
|
fn is_read_vectored(&self) -> bool {
|
||||||
self.inner.is_read_vectored()
|
self.inner.is_read_vectored()
|
||||||
|
@ -859,6 +802,96 @@ impl Seek for &File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl Read for File {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
(&*self).read(buf)
|
||||||
|
}
|
||||||
|
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||||
|
(&*self).read_vectored(bufs)
|
||||||
|
}
|
||||||
|
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||||
|
(&*self).read_buf(cursor)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_read_vectored(&self) -> bool {
|
||||||
|
(&&*self).is_read_vectored()
|
||||||
|
}
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
(&*self).read_to_end(buf)
|
||||||
|
}
|
||||||
|
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||||
|
(&*self).read_to_string(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl Write for File {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
(&*self).write(buf)
|
||||||
|
}
|
||||||
|
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||||
|
(&*self).write_vectored(bufs)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_write_vectored(&self) -> bool {
|
||||||
|
(&&*self).is_write_vectored()
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
(&*self).flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl Seek for File {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||||
|
(&*self).seek(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "io_traits_arc", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
impl Read for Arc<File> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
(&**self).read(buf)
|
||||||
|
}
|
||||||
|
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||||
|
(&**self).read_vectored(bufs)
|
||||||
|
}
|
||||||
|
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
|
||||||
|
(&**self).read_buf(cursor)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_read_vectored(&self) -> bool {
|
||||||
|
(&**self).is_read_vectored()
|
||||||
|
}
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
(&**self).read_to_end(buf)
|
||||||
|
}
|
||||||
|
fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
|
||||||
|
(&**self).read_to_string(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "io_traits_arc", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
impl Write for Arc<File> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
(&**self).write(buf)
|
||||||
|
}
|
||||||
|
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||||
|
(&**self).write_vectored(bufs)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn is_write_vectored(&self) -> bool {
|
||||||
|
(&**self).is_write_vectored()
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
(&**self).flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "io_traits_arc", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
impl Seek for Arc<File> {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||||
|
(&**self).seek(pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl OpenOptions {
|
impl OpenOptions {
|
||||||
/// Creates a blank new set of options ready for configuration.
|
/// Creates a blank new set of options ready for configuration.
|
||||||
///
|
///
|
||||||
|
|
|
@ -99,6 +99,13 @@ impl<'data> BorrowedBuf<'data> {
|
||||||
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
|
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the filled portion of the buffer.
|
||||||
|
#[inline]
|
||||||
|
pub fn filled_mut(&mut self) -> &mut [u8] {
|
||||||
|
// SAFETY: We only slice the filled part of the buffer, which is always valid
|
||||||
|
unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a cursor over the unfilled part of the buffer.
|
/// Returns a cursor over the unfilled part of the buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
|
pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
|
||||||
|
|
|
@ -21,26 +21,26 @@ pub use self::arch::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t,
|
||||||
|
|
||||||
#[cfg(any(target_arch = "arm", target_arch = "x86"))]
|
#[cfg(any(target_arch = "arm", target_arch = "x86"))]
|
||||||
mod arch {
|
mod arch {
|
||||||
use crate::os::raw::{c_longlong, c_uchar, c_uint, c_ulong, c_ulonglong};
|
use crate::os::raw::{c_long, c_longlong, c_uchar, c_uint, c_ulong, c_ulonglong};
|
||||||
use crate::os::unix::raw::{gid_t, uid_t};
|
use crate::os::unix::raw::{gid_t, uid_t};
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type dev_t = u64;
|
pub type dev_t = u32;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type mode_t = u32;
|
pub type mode_t = c_uint;
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blkcnt_t = u64;
|
pub type blkcnt_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blksize_t = u64;
|
pub type blksize_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type ino_t = u64;
|
pub type ino_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type nlink_t = u64;
|
pub type nlink_t = u32;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type off_t = u64;
|
pub type off_t = i32;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type time_t = i64;
|
pub type time_t = c_long;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -70,18 +70,20 @@ mod arch {
|
||||||
pub st_blksize: u32,
|
pub st_blksize: u32,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_blocks: c_ulonglong,
|
pub st_blocks: c_ulonglong,
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime: c_ulong,
|
pub st_atime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime_nsec: c_ulong,
|
pub st_atime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime: c_ulong,
|
pub st_mtime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime_nsec: c_ulong,
|
pub st_mtime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime: c_ulong,
|
pub st_ctime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime_nsec: c_ulong,
|
pub st_ctime_nsec: c_long,
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ino: c_ulonglong,
|
pub st_ino: c_ulonglong,
|
||||||
}
|
}
|
||||||
|
@ -89,26 +91,26 @@ mod arch {
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
mod arch {
|
mod arch {
|
||||||
use crate::os::raw::{c_uchar, c_ulong};
|
use crate::os::raw::{c_int, c_long, c_uint, c_ulong};
|
||||||
use crate::os::unix::raw::{gid_t, uid_t};
|
use crate::os::unix::raw::{gid_t, uid_t};
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type dev_t = u64;
|
pub type dev_t = u64;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type mode_t = u32;
|
pub type mode_t = c_uint;
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blkcnt_t = u64;
|
pub type blkcnt_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blksize_t = u64;
|
pub type blksize_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type ino_t = u64;
|
pub type ino_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type nlink_t = u64;
|
pub type nlink_t = u32;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type off_t = u64;
|
pub type off_t = i64;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type time_t = i64;
|
pub type time_t = c_long;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -117,9 +119,7 @@ mod arch {
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_dev: dev_t,
|
pub st_dev: dev_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub __pad0: [c_uchar; 4],
|
pub st_ino: ino_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
|
||||||
pub __st_ino: ino_t,
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mode: mode_t,
|
pub st_mode: mode_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
|
@ -131,27 +131,33 @@ mod arch {
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_rdev: dev_t,
|
pub st_rdev: dev_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub __pad3: [c_uchar; 4],
|
pub __pad1: c_ulong,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_size: off_t,
|
pub st_size: off_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_blksize: blksize_t,
|
pub st_blksize: c_int,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_blocks: blkcnt_t,
|
pub __pad2: c_int,
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
|
pub st_blocks: c_long,
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime: time_t,
|
pub st_atime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime_nsec: c_ulong,
|
pub st_atime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime: time_t,
|
pub st_mtime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime_nsec: c_ulong,
|
pub st_mtime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime: time_t,
|
pub st_ctime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime_nsec: c_ulong,
|
pub st_ctime_nsec: c_long,
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ino: ino_t,
|
pub __unused4: c_uint,
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
|
pub __unused5: c_uint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,20 +169,20 @@ mod arch {
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type dev_t = u64;
|
pub type dev_t = u64;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type mode_t = u32;
|
pub type mode_t = c_uint;
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blkcnt_t = u64;
|
pub type blkcnt_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type blksize_t = u64;
|
pub type blksize_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type ino_t = u64;
|
pub type ino_t = c_ulong;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type nlink_t = u32;
|
pub type nlink_t = u32;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type off_t = u64;
|
pub type off_t = i64;
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub type time_t = i64;
|
pub type time_t = c_long;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -195,25 +201,30 @@ mod arch {
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_gid: gid_t,
|
pub st_gid: gid_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
|
pub __pad0: c_uint,
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_rdev: dev_t,
|
pub st_rdev: dev_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_size: i64,
|
pub st_size: off_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_blksize: c_long,
|
pub st_blksize: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_blocks: c_long,
|
pub st_blocks: c_long,
|
||||||
|
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime: c_ulong,
|
pub st_atime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_atime_nsec: c_ulong,
|
pub st_atime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime: c_ulong,
|
pub st_mtime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_mtime_nsec: c_ulong,
|
pub st_mtime_nsec: c_long,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime: c_ulong,
|
pub st_ctime: time_t,
|
||||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
pub st_ctime_nsec: c_ulong,
|
pub st_ctime_nsec: c_long,
|
||||||
__unused: [c_long; 3],
|
|
||||||
|
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||||
|
pub __pad3: [c_long; 3],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::process::Command;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use crate::cache::{Cache, Interned, INTERNER};
|
use crate::cache::{Cache, Interned, INTERNER};
|
||||||
use crate::config::{SplitDebuginfo, TargetSelection};
|
use crate::config::{DryRun, SplitDebuginfo, TargetSelection};
|
||||||
use crate::doc;
|
use crate::doc;
|
||||||
use crate::flags::{Color, Subcommand};
|
use crate::flags::{Color, Subcommand};
|
||||||
use crate::install;
|
use crate::install;
|
||||||
|
@ -281,11 +281,15 @@ impl StepDescription {
|
||||||
|
|
||||||
fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
|
fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
|
||||||
if builder.config.exclude.iter().any(|e| pathset.has(&e, builder.kind)) {
|
if builder.config.exclude.iter().any(|e| pathset.has(&e, builder.kind)) {
|
||||||
println!("Skipping {:?} because it is excluded", pathset);
|
if !matches!(builder.config.dry_run, DryRun::SelfCheck) {
|
||||||
|
println!("Skipping {:?} because it is excluded", pathset);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !builder.config.exclude.is_empty() {
|
if !builder.config.exclude.is_empty()
|
||||||
|
&& !matches!(builder.config.dry_run, DryRun::SelfCheck)
|
||||||
|
{
|
||||||
builder.verbose(&format!(
|
builder.verbose(&format!(
|
||||||
"{:?} not skipped for {:?} -- not in {:?}",
|
"{:?} not skipped for {:?} -- not in {:?}",
|
||||||
pathset, self.name, builder.config.exclude
|
pathset, self.name, builder.config.exclude
|
||||||
|
|
|
@ -688,8 +688,8 @@ fn cp_rustc_component_to_ci_sysroot(
|
||||||
contents: Vec<String>,
|
contents: Vec<String>,
|
||||||
) {
|
) {
|
||||||
let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
|
let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
|
||||||
|
let ci_rustc_dir = builder.config.ci_rustc_dir();
|
||||||
|
|
||||||
let ci_rustc_dir = builder.out.join(&*builder.build.build.triple).join("ci-rustc");
|
|
||||||
for file in contents {
|
for file in contents {
|
||||||
let src = ci_rustc_dir.join(&file);
|
let src = ci_rustc_dir.join(&file);
|
||||||
let dst = sysroot.join(file);
|
let dst = sysroot.join(file);
|
||||||
|
@ -1424,7 +1424,7 @@ impl Step for Sysroot {
|
||||||
// FIXME: this is wrong when compiler.host != build, but we don't support that today
|
// FIXME: this is wrong when compiler.host != build, but we don't support that today
|
||||||
OsStr::new(std::env::consts::DLL_EXTENSION),
|
OsStr::new(std::env::consts::DLL_EXTENSION),
|
||||||
];
|
];
|
||||||
let ci_rustc_dir = builder.ci_rustc_dir(builder.config.build);
|
let ci_rustc_dir = builder.config.ci_rustc_dir();
|
||||||
builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
builder.cp_filtered(&ci_rustc_dir, &sysroot, &|path| {
|
||||||
if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {
|
if path.extension().map_or(true, |ext| !filtered_extensions.contains(&ext)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1375,6 +1375,25 @@ impl Config {
|
||||||
let mut omit_git_hash = None;
|
let mut omit_git_hash = None;
|
||||||
|
|
||||||
if let Some(rust) = toml.rust {
|
if let Some(rust) = toml.rust {
|
||||||
|
set(&mut config.channel, rust.channel);
|
||||||
|
|
||||||
|
config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
|
||||||
|
// This list is incomplete, please help by expanding it!
|
||||||
|
if config.download_rustc_commit.is_some() {
|
||||||
|
// We need the channel used by the downloaded compiler to match the one we set for rustdoc;
|
||||||
|
// otherwise rustdoc-ui tests break.
|
||||||
|
let ci_channel = t!(fs::read_to_string(config.src.join("src/ci/channel")));
|
||||||
|
let ci_channel = ci_channel.trim_end();
|
||||||
|
if config.channel != ci_channel
|
||||||
|
&& !(config.channel == "dev" && ci_channel == "nightly")
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"setting rust.channel={} is incompatible with download-rustc",
|
||||||
|
config.channel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug = rust.debug;
|
debug = rust.debug;
|
||||||
debug_assertions = rust.debug_assertions;
|
debug_assertions = rust.debug_assertions;
|
||||||
debug_assertions_std = rust.debug_assertions_std;
|
debug_assertions_std = rust.debug_assertions_std;
|
||||||
|
@ -1386,6 +1405,7 @@ impl Config {
|
||||||
debuginfo_level_std = rust.debuginfo_level_std;
|
debuginfo_level_std = rust.debuginfo_level_std;
|
||||||
debuginfo_level_tools = rust.debuginfo_level_tools;
|
debuginfo_level_tools = rust.debuginfo_level_tools;
|
||||||
debuginfo_level_tests = rust.debuginfo_level_tests;
|
debuginfo_level_tests = rust.debuginfo_level_tests;
|
||||||
|
|
||||||
config.rust_split_debuginfo = rust
|
config.rust_split_debuginfo = rust
|
||||||
.split_debuginfo
|
.split_debuginfo
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
@ -1401,7 +1421,6 @@ impl Config {
|
||||||
set(&mut config.jemalloc, rust.jemalloc);
|
set(&mut config.jemalloc, rust.jemalloc);
|
||||||
set(&mut config.test_compare_mode, rust.test_compare_mode);
|
set(&mut config.test_compare_mode, rust.test_compare_mode);
|
||||||
set(&mut config.backtrace, rust.backtrace);
|
set(&mut config.backtrace, rust.backtrace);
|
||||||
set(&mut config.channel, rust.channel);
|
|
||||||
config.description = rust.description;
|
config.description = rust.description;
|
||||||
set(&mut config.rust_dist_src, rust.dist_src);
|
set(&mut config.rust_dist_src, rust.dist_src);
|
||||||
set(&mut config.verbose_tests, rust.verbose_tests);
|
set(&mut config.verbose_tests, rust.verbose_tests);
|
||||||
|
@ -1442,8 +1461,6 @@ impl Config {
|
||||||
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
|
config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
|
||||||
config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
|
config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
|
||||||
config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
|
config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
|
||||||
config.download_rustc_commit = config.download_ci_rustc_commit(rust.download_rustc);
|
|
||||||
|
|
||||||
config.rust_lto = rust
|
config.rust_lto = rust
|
||||||
.lto
|
.lto
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
@ -1555,6 +1572,11 @@ impl Config {
|
||||||
let mut target = Target::from_triple(&triple);
|
let mut target = Target::from_triple(&triple);
|
||||||
|
|
||||||
if let Some(ref s) = cfg.llvm_config {
|
if let Some(ref s) = cfg.llvm_config {
|
||||||
|
if config.download_rustc_commit.is_some() && triple == &*config.build.triple {
|
||||||
|
panic!(
|
||||||
|
"setting llvm_config for the host is incompatible with download-rustc"
|
||||||
|
);
|
||||||
|
}
|
||||||
target.llvm_config = Some(config.src.join(s));
|
target.llvm_config = Some(config.src.join(s));
|
||||||
}
|
}
|
||||||
target.llvm_has_rust_patches = cfg.llvm_has_rust_patches;
|
target.llvm_has_rust_patches = cfg.llvm_has_rust_patches;
|
||||||
|
@ -1825,6 +1847,12 @@ impl Config {
|
||||||
self.out.join(&*self.build.triple).join("ci-llvm")
|
self.out.join(&*self.build.triple).join("ci-llvm")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Directory where the extracted `rustc-dev` component is stored.
|
||||||
|
pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
|
||||||
|
assert!(self.download_rustc());
|
||||||
|
self.out.join(self.build.triple).join("ci-rustc")
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine whether llvm should be linked dynamically.
|
/// Determine whether llvm should be linked dynamically.
|
||||||
///
|
///
|
||||||
/// If `false`, llvm should be linked statically.
|
/// If `false`, llvm should be linked statically.
|
||||||
|
@ -1860,11 +1888,11 @@ impl Config {
|
||||||
self.download_rustc_commit().is_some()
|
self.download_rustc_commit().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn download_rustc_commit(&self) -> Option<&'static str> {
|
pub(crate) fn download_rustc_commit(&self) -> Option<&str> {
|
||||||
static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new();
|
static DOWNLOAD_RUSTC: OnceCell<Option<String>> = OnceCell::new();
|
||||||
if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() {
|
if self.dry_run() && DOWNLOAD_RUSTC.get().is_none() {
|
||||||
// avoid trying to actually download the commit
|
// avoid trying to actually download the commit
|
||||||
return None;
|
return self.download_rustc_commit.as_deref();
|
||||||
}
|
}
|
||||||
|
|
||||||
DOWNLOAD_RUSTC
|
DOWNLOAD_RUSTC
|
||||||
|
|
|
@ -1074,11 +1074,7 @@ impl Step for Cargo {
|
||||||
|
|
||||||
tarball.add_file(&cargo, "bin", 0o755);
|
tarball.add_file(&cargo, "bin", 0o755);
|
||||||
tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
|
tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644);
|
||||||
tarball.add_renamed_file(
|
tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo");
|
||||||
etc.join("cargo.bashcomp.sh"),
|
|
||||||
"src/etc/bash_completion.d",
|
|
||||||
"cargo",
|
|
||||||
);
|
|
||||||
tarball.add_dir(etc.join("man"), "share/man/man1");
|
tarball.add_dir(etc.join("man"), "share/man/man1");
|
||||||
tarball.add_legal_and_readme_to("share/doc/cargo");
|
tarball.add_legal_and_readme_to("share/doc/cargo");
|
||||||
|
|
||||||
|
|
|
@ -402,7 +402,11 @@ impl Config {
|
||||||
|
|
||||||
fn ci_component_contents(&self, stamp_file: &str) -> Vec<String> {
|
fn ci_component_contents(&self, stamp_file: &str) -> Vec<String> {
|
||||||
assert!(self.download_rustc());
|
assert!(self.download_rustc());
|
||||||
let ci_rustc_dir = self.out.join(&*self.build.triple).join("ci-rustc");
|
if self.dry_run() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
let ci_rustc_dir = self.ci_rustc_dir();
|
||||||
let stamp_file = ci_rustc_dir.join(stamp_file);
|
let stamp_file = ci_rustc_dir.join(stamp_file);
|
||||||
let contents_file = t!(File::open(&stamp_file), stamp_file.display().to_string());
|
let contents_file = t!(File::open(&stamp_file), stamp_file.display().to_string());
|
||||||
t!(BufReader::new(contents_file).lines().collect())
|
t!(BufReader::new(contents_file).lines().collect())
|
||||||
|
@ -419,7 +423,7 @@ impl Config {
|
||||||
self.download_toolchain(
|
self.download_toolchain(
|
||||||
&version,
|
&version,
|
||||||
"ci-rustc",
|
"ci-rustc",
|
||||||
commit,
|
&format!("{commit}-{}", self.llvm_assertions),
|
||||||
&extra_components,
|
&extra_components,
|
||||||
Self::download_ci_component,
|
Self::download_ci_component,
|
||||||
);
|
);
|
||||||
|
@ -495,8 +499,15 @@ impl Config {
|
||||||
|
|
||||||
/// Download a single component of a CI-built toolchain (not necessarily a published nightly).
|
/// Download a single component of a CI-built toolchain (not necessarily a published nightly).
|
||||||
// NOTE: intentionally takes an owned string to avoid downloading multiple times by accident
|
// NOTE: intentionally takes an owned string to avoid downloading multiple times by accident
|
||||||
fn download_ci_component(&self, filename: String, prefix: &str, commit: &str) {
|
fn download_ci_component(&self, filename: String, prefix: &str, commit_with_assertions: &str) {
|
||||||
Self::download_component(self, DownloadSource::CI, filename, prefix, commit, "ci-rustc")
|
Self::download_component(
|
||||||
|
self,
|
||||||
|
DownloadSource::CI,
|
||||||
|
filename,
|
||||||
|
prefix,
|
||||||
|
commit_with_assertions,
|
||||||
|
"ci-rustc",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download_component(
|
fn download_component(
|
||||||
|
@ -516,11 +527,18 @@ impl Config {
|
||||||
let bin_root = self.out.join(self.build.triple).join(destination);
|
let bin_root = self.out.join(self.build.triple).join(destination);
|
||||||
let tarball = cache_dir.join(&filename);
|
let tarball = cache_dir.join(&filename);
|
||||||
let (base_url, url, should_verify) = match mode {
|
let (base_url, url, should_verify) = match mode {
|
||||||
DownloadSource::CI => (
|
DownloadSource::CI => {
|
||||||
self.stage0_metadata.config.artifacts_server.clone(),
|
let dist_server = if self.llvm_assertions {
|
||||||
format!("{key}/{filename}"),
|
self.stage0_metadata.config.artifacts_with_llvm_assertions_server.clone()
|
||||||
false,
|
} else {
|
||||||
),
|
self.stage0_metadata.config.artifacts_server.clone()
|
||||||
|
};
|
||||||
|
let url = format!(
|
||||||
|
"{}/{filename}",
|
||||||
|
key.strip_suffix(&format!("-{}", self.llvm_assertions)).unwrap()
|
||||||
|
);
|
||||||
|
(dist_server, url, false)
|
||||||
|
}
|
||||||
DownloadSource::Dist => {
|
DownloadSource::Dist => {
|
||||||
let dist_server = env::var("RUSTUP_DIST_SERVER")
|
let dist_server = env::var("RUSTUP_DIST_SERVER")
|
||||||
.unwrap_or(self.stage0_metadata.config.dist_server.to_string());
|
.unwrap_or(self.stage0_metadata.config.dist_server.to_string());
|
||||||
|
|
|
@ -822,11 +822,6 @@ impl Build {
|
||||||
self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
|
self.stage_out(compiler, mode).join(&*target.triple).join(self.cargo_dir())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Directory where the extracted `rustc-dev` component is stored.
|
|
||||||
fn ci_rustc_dir(&self, target: TargetSelection) -> PathBuf {
|
|
||||||
self.out.join(&*target.triple).join("ci-rustc")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Root output directory for LLVM compiled for `target`
|
/// Root output directory for LLVM compiled for `target`
|
||||||
///
|
///
|
||||||
/// Note that if LLVM is configured externally then the directory returned
|
/// Note that if LLVM is configured externally then the directory returned
|
||||||
|
|
|
@ -2348,7 +2348,7 @@ impl Step for Crate {
|
||||||
// `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`,
|
// `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`,
|
||||||
// but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`.
|
// but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`.
|
||||||
// Override it.
|
// Override it.
|
||||||
if builder.download_rustc() {
|
if builder.download_rustc() && compiler.stage > 0 {
|
||||||
let sysroot = builder
|
let sysroot = builder
|
||||||
.out
|
.out
|
||||||
.join(compiler.host.triple)
|
.join(compiler.host.triple)
|
||||||
|
|
|
@ -90,7 +90,7 @@ x--expand-yaml-anchors--remove:
|
||||||
<<: *base-job
|
<<: *base-job
|
||||||
|
|
||||||
- &job-macos-xl
|
- &job-macos-xl
|
||||||
os: macos-latest # We use the standard runner for now
|
os: macos-13 # We use the standard runner for now
|
||||||
<<: *base-job
|
<<: *base-job
|
||||||
|
|
||||||
- &job-windows-8c
|
- &job-windows-8c
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 21cf840842bdf768a798869f06373c96c1cc5122
|
Subproject commit 668c64760b5c7ea654facb4ba5fe9faddfda27cc
|
|
@ -1 +1 @@
|
||||||
Subproject commit f63e578b92ff43e8cc38fcaa257b660f45c8a8c2
|
Subproject commit 2751bdcef125468ea2ee006c11992cd1405aebe5
|
|
@ -1 +1 @@
|
||||||
Subproject commit f2aed2fe8e9f55508c86ba3aa4b6789b18a08a22
|
Subproject commit 1e5556dd1b864109985d5871616ae6b9164bcead
|
|
@ -1 +1 @@
|
||||||
Subproject commit c369e4b489332f8721fbae630354fa83385d457d
|
Subproject commit 302b995bcb24b70fd883980fd174738c3a10b705
|
|
@ -1 +1 @@
|
||||||
Subproject commit 5ca365eac678cb0d41a20b3204546d6ed70c7171
|
Subproject commit 1ea0178266b3f3f613b0fabdaf16a83961c99cdb
|
|
@ -1 +1 @@
|
||||||
Subproject commit 57636d6926762861f34e030d52ca25a71e95e5bf
|
Subproject commit 8a87926a985ce32ca1fad1be4008ee161a0b91eb
|
|
@ -1 +1 @@
|
||||||
Subproject commit 17fe3e948498c50e208047a750f17d6a8d89669b
|
Subproject commit b5a12d95e32ae53791cc6ab44417774667ed2ac6
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue