mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-04 19:12:50 +00:00
Rollup merge of #94143 - est31:let_else_const_eval, r=lcnr
rustc_const_eval: adopt let else in more places Continuation of #89933, #91018, #91481, #93046, #93590, #94011. I have extended my clippy lint to also recognize tuple passing and match statements. The diff caused by fixing it is way above 1 thousand lines. Thus, I split it up into multiple pull requests to make reviewing easier. This PR handles rustc_const_eval.
This commit is contained in:
commit
ea7f7f7c4c
@ -231,9 +231,8 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
|
|||||||
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
|
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
|
||||||
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
|
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
|
||||||
let ty = key.value.instance.ty(tcx, key.param_env);
|
let ty = key.value.instance.ty(tcx, key.param_env);
|
||||||
let substs = match ty.kind() {
|
let ty::FnDef(_, substs) = ty.kind() else {
|
||||||
ty::FnDef(_, substs) => substs,
|
bug!("intrinsic with type {:?}", ty);
|
||||||
_ => bug!("intrinsic with type {:?}", ty),
|
|
||||||
};
|
};
|
||||||
return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
|
return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
|
||||||
let span = tcx.def_span(def_id);
|
let span = tcx.def_span(def_id);
|
||||||
|
@ -318,15 +318,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
|||||||
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
|
let intrinsic_name = ecx.tcx.item_name(instance.def_id());
|
||||||
|
|
||||||
// CTFE-specific intrinsics.
|
// CTFE-specific intrinsics.
|
||||||
let (dest, ret) = match ret {
|
let Some((dest, ret)) = ret else {
|
||||||
None => {
|
return Err(ConstEvalErrKind::NeedsRfc(format!(
|
||||||
return Err(ConstEvalErrKind::NeedsRfc(format!(
|
"calling intrinsic `{}`",
|
||||||
"calling intrinsic `{}`",
|
intrinsic_name
|
||||||
intrinsic_name
|
))
|
||||||
))
|
.into());
|
||||||
.into());
|
|
||||||
}
|
|
||||||
Some(p) => p,
|
|
||||||
};
|
};
|
||||||
match intrinsic_name {
|
match intrinsic_name {
|
||||||
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
|
||||||
|
@ -631,15 +631,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
// the last field). Can't have foreign types here, how would we
|
// the last field). Can't have foreign types here, how would we
|
||||||
// adjust alignment and size for them?
|
// adjust alignment and size for them?
|
||||||
let field = layout.field(self, layout.fields.count() - 1);
|
let field = layout.field(self, layout.fields.count() - 1);
|
||||||
let (unsized_size, unsized_align) =
|
let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else {
|
||||||
match self.size_and_align_of(metadata, &field)? {
|
// A field with an extern type. We don't know the actual dynamic size
|
||||||
Some(size_and_align) => size_and_align,
|
// or the alignment.
|
||||||
None => {
|
return Ok(None);
|
||||||
// A field with an extern type. We don't know the actual dynamic size
|
};
|
||||||
// or the alignment.
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME (#26403, #27023): We should be adding padding
|
// FIXME (#26403, #27023): We should be adding padding
|
||||||
// to `sized_size` (to accommodate the `unsized_align`
|
// to `sized_size` (to accommodate the `unsized_align`
|
||||||
|
@ -84,22 +84,19 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
|
|||||||
trace!("intern_shallow {:?} with {:?}", alloc_id, mode);
|
trace!("intern_shallow {:?} with {:?}", alloc_id, mode);
|
||||||
// remove allocation
|
// remove allocation
|
||||||
let tcx = ecx.tcx;
|
let tcx = ecx.tcx;
|
||||||
let (kind, mut alloc) = match ecx.memory.alloc_map.remove(&alloc_id) {
|
let Some((kind, mut alloc)) = ecx.memory.alloc_map.remove(&alloc_id) else {
|
||||||
Some(entry) => entry,
|
// Pointer not found in local memory map. It is either a pointer to the global
|
||||||
None => {
|
// map, or dangling.
|
||||||
// Pointer not found in local memory map. It is either a pointer to the global
|
// If the pointer is dangling (neither in local nor global memory), we leave it
|
||||||
// map, or dangling.
|
// to validation to error -- it has the much better error messages, pointing out where
|
||||||
// If the pointer is dangling (neither in local nor global memory), we leave it
|
// in the value the dangling reference lies.
|
||||||
// to validation to error -- it has the much better error messages, pointing out where
|
// The `delay_span_bug` ensures that we don't forget such a check in validation.
|
||||||
// in the value the dangling reference lies.
|
if tcx.get_global_alloc(alloc_id).is_none() {
|
||||||
// The `delay_span_bug` ensures that we don't forget such a check in validation.
|
tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
|
||||||
if tcx.get_global_alloc(alloc_id).is_none() {
|
|
||||||
tcx.sess.delay_span_bug(ecx.tcx.span, "tried to intern dangling pointer");
|
|
||||||
}
|
|
||||||
// treat dangling pointers like other statics
|
|
||||||
// just to stop trying to recurse into them
|
|
||||||
return Some(IsStaticOrFn);
|
|
||||||
}
|
}
|
||||||
|
// treat dangling pointers like other statics
|
||||||
|
// just to stop trying to recurse into them
|
||||||
|
return Some(IsStaticOrFn);
|
||||||
};
|
};
|
||||||
// This match is just a canary for future changes to `MemoryKind`, which most likely need
|
// This match is just a canary for future changes to `MemoryKind`, which most likely need
|
||||||
// changes in this function.
|
// changes in this function.
|
||||||
|
@ -291,21 +291,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (alloc_kind, mut alloc) = match self.alloc_map.remove(&alloc_id) {
|
let Some((alloc_kind, mut alloc)) = self.alloc_map.remove(&alloc_id) else {
|
||||||
Some(alloc) => alloc,
|
// Deallocating global memory -- always an error
|
||||||
None => {
|
return Err(match self.tcx.get_global_alloc(alloc_id) {
|
||||||
// Deallocating global memory -- always an error
|
Some(GlobalAlloc::Function(..)) => {
|
||||||
return Err(match self.tcx.get_global_alloc(alloc_id) {
|
err_ub_format!("deallocating {}, which is a function", alloc_id)
|
||||||
Some(GlobalAlloc::Function(..)) => {
|
|
||||||
err_ub_format!("deallocating {}, which is a function", alloc_id)
|
|
||||||
}
|
|
||||||
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
|
|
||||||
err_ub_format!("deallocating {}, which is static memory", alloc_id)
|
|
||||||
}
|
|
||||||
None => err_ub!(PointerUseAfterFree(alloc_id)),
|
|
||||||
}
|
}
|
||||||
.into());
|
Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
|
||||||
|
err_ub_format!("deallocating {}, which is static memory", alloc_id)
|
||||||
|
}
|
||||||
|
None => err_ub!(PointerUseAfterFree(alloc_id)),
|
||||||
}
|
}
|
||||||
|
.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
if alloc.mutability == Mutability::Not {
|
if alloc.mutability == Mutability::Not {
|
||||||
@ -957,9 +954,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||||||
ptr: Pointer<Option<M::PointerTag>>,
|
ptr: Pointer<Option<M::PointerTag>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
) -> InterpResult<'tcx, &[u8]> {
|
) -> InterpResult<'tcx, &[u8]> {
|
||||||
let alloc_ref = match self.get(ptr, size, Align::ONE)? {
|
let Some(alloc_ref) = self.get(ptr, size, Align::ONE)? else {
|
||||||
Some(a) => a,
|
// zero-sized access
|
||||||
None => return Ok(&[]), // zero-sized access
|
return Ok(&[]);
|
||||||
};
|
};
|
||||||
// Side-step AllocRef and directly access the underlying bytes more efficiently.
|
// Side-step AllocRef and directly access the underlying bytes more efficiently.
|
||||||
// (We are staying inside the bounds here so all is good.)
|
// (We are staying inside the bounds here so all is good.)
|
||||||
@ -983,17 +980,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||||||
assert_eq!(lower, len, "can only write iterators with a precise length");
|
assert_eq!(lower, len, "can only write iterators with a precise length");
|
||||||
|
|
||||||
let size = Size::from_bytes(len);
|
let size = Size::from_bytes(len);
|
||||||
let alloc_ref = match self.get_mut(ptr, size, Align::ONE)? {
|
let Some(alloc_ref) = self.get_mut(ptr, size, Align::ONE)? else {
|
||||||
Some(alloc_ref) => alloc_ref,
|
// zero-sized access
|
||||||
None => {
|
assert_matches!(
|
||||||
// zero-sized access
|
src.next(),
|
||||||
assert_matches!(
|
None,
|
||||||
src.next(),
|
"iterator said it was empty but returned an element"
|
||||||
None,
|
);
|
||||||
"iterator said it was empty but returned an element"
|
return Ok(());
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Side-step AllocRef and directly access the underlying bytes more efficiently.
|
// Side-step AllocRef and directly access the underlying bytes more efficiently.
|
||||||
@ -1043,18 +1037,18 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||||||
// and once below to get the underlying `&[mut] Allocation`.
|
// and once below to get the underlying `&[mut] Allocation`.
|
||||||
|
|
||||||
// Source alloc preparations and access hooks.
|
// Source alloc preparations and access hooks.
|
||||||
let (src_alloc_id, src_offset, src) = match src_parts {
|
let Some((src_alloc_id, src_offset, src)) = src_parts else {
|
||||||
None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
|
// Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
|
||||||
Some(src_ptr) => src_ptr,
|
return Ok(());
|
||||||
};
|
};
|
||||||
let src_alloc = self.get_raw(src_alloc_id)?;
|
let src_alloc = self.get_raw(src_alloc_id)?;
|
||||||
let src_range = alloc_range(src_offset, size);
|
let src_range = alloc_range(src_offset, size);
|
||||||
M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?;
|
M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?;
|
||||||
// We need the `dest` ptr for the next operation, so we get it now.
|
// We need the `dest` ptr for the next operation, so we get it now.
|
||||||
// We already did the source checks and called the hooks so we are good to return early.
|
// We already did the source checks and called the hooks so we are good to return early.
|
||||||
let (dest_alloc_id, dest_offset, dest) = match dest_parts {
|
let Some((dest_alloc_id, dest_offset, dest)) = dest_parts else {
|
||||||
None => return Ok(()), // Zero-sized *destiantion*.
|
// Zero-sized *destination*.
|
||||||
Some(dest_ptr) => dest_ptr,
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
// This checks relocation edges on the src, which needs to happen before
|
// This checks relocation edges on the src, which needs to happen before
|
||||||
|
@ -258,15 +258,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let alloc = match self.get_alloc(mplace)? {
|
let Some(alloc) = self.get_alloc(mplace)? else {
|
||||||
Some(ptr) => ptr,
|
return Ok(Some(ImmTy {
|
||||||
None => {
|
// zero-sized type
|
||||||
return Ok(Some(ImmTy {
|
imm: Scalar::ZST.into(),
|
||||||
// zero-sized type
|
layout: mplace.layout,
|
||||||
imm: Scalar::ZST.into(),
|
}));
|
||||||
layout: mplace.layout,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match mplace.layout.abi {
|
match mplace.layout.abi {
|
||||||
|
@ -420,9 +420,8 @@ where
|
|||||||
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
|
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
|
||||||
{
|
{
|
||||||
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
let len = base.len(self)?; // also asserts that we have a type where this makes sense
|
||||||
let stride = match base.layout.fields {
|
let FieldsShape::Array { stride, .. } = base.layout.fields else {
|
||||||
FieldsShape::Array { stride, .. } => stride,
|
span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout");
|
||||||
_ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"),
|
|
||||||
};
|
};
|
||||||
let layout = base.layout.field(self, 0);
|
let layout = base.layout.field(self, 0);
|
||||||
let dl = &self.tcx.data_layout;
|
let dl = &self.tcx.data_layout;
|
||||||
@ -747,9 +746,9 @@ where
|
|||||||
|
|
||||||
// Invalid places are a thing: the return place of a diverging function
|
// Invalid places are a thing: the return place of a diverging function
|
||||||
let tcx = *self.tcx;
|
let tcx = *self.tcx;
|
||||||
let mut alloc = match self.get_alloc_mut(dest)? {
|
let Some(mut alloc) = self.get_alloc_mut(dest)? else {
|
||||||
Some(a) => a,
|
// zero-sized access
|
||||||
None => return Ok(()), // zero-sized access
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: We should check that there are dest.layout.size many bytes available in
|
// FIXME: We should check that there are dest.layout.size many bytes available in
|
||||||
|
@ -46,15 +46,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let loc = match self.frame().loc {
|
let Ok(loc) = self.frame().loc else {
|
||||||
Ok(loc) => loc,
|
// We are unwinding and this fn has no cleanup code.
|
||||||
Err(_) => {
|
// Just go on unwinding.
|
||||||
// We are unwinding and this fn has no cleanup code.
|
trace!("unwinding: skipping frame");
|
||||||
// Just go on unwinding.
|
self.pop_stack_frame(/* unwinding */ true)?;
|
||||||
trace!("unwinding: skipping frame");
|
return Ok(true);
|
||||||
self.pop_stack_frame(/* unwinding */ true)?;
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let basic_block = &self.body().basic_blocks()[loc.block];
|
let basic_block = &self.body().basic_blocks()[loc.block];
|
||||||
|
|
||||||
|
@ -321,10 +321,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
| ty::InstanceDef::CloneShim(..)
|
| ty::InstanceDef::CloneShim(..)
|
||||||
| ty::InstanceDef::Item(_) => {
|
| ty::InstanceDef::Item(_) => {
|
||||||
// We need MIR for this fn
|
// We need MIR for this fn
|
||||||
let (body, instance) =
|
let Some((body, instance)) =
|
||||||
match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? {
|
M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? else {
|
||||||
Some(body) => body,
|
return Ok(());
|
||||||
None => return Ok(()),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Compute callee information using the `instance` returned by
|
// Compute callee information using the `instance` returned by
|
||||||
|
@ -851,12 +851,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
|||||||
// to reject those pointers, we just do not have the machinery to
|
// to reject those pointers, we just do not have the machinery to
|
||||||
// talk about parts of a pointer.
|
// talk about parts of a pointer.
|
||||||
// We also accept uninit, for consistency with the slow path.
|
// We also accept uninit, for consistency with the slow path.
|
||||||
let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? {
|
let Some(alloc) = self.ecx.memory.get(mplace.ptr, size, mplace.align)? else {
|
||||||
Some(a) => a,
|
// Size 0, nothing more to check.
|
||||||
None => {
|
return Ok(());
|
||||||
// Size 0, nothing more to check.
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
|
let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);
|
||||||
|
@ -134,11 +134,8 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
|||||||
.find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
|
.find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
|
||||||
.map(|(bb, _)| bb);
|
.map(|(bb, _)| bb);
|
||||||
|
|
||||||
let return_block = match return_block {
|
let Some(return_block) = return_block else {
|
||||||
None => {
|
return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
|
||||||
return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
|
|
||||||
}
|
|
||||||
Some(bb) => bb,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let return_loc = ccx.body.terminator_loc(return_block);
|
let return_loc = ccx.body.terminator_loc(return_block);
|
||||||
|
@ -747,15 +747,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||||||
if loc.statement_index < num_stmts {
|
if loc.statement_index < num_stmts {
|
||||||
let (mut rvalue, source_info) = {
|
let (mut rvalue, source_info) = {
|
||||||
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
let statement = &mut self.source[loc.block].statements[loc.statement_index];
|
||||||
let rhs = match statement.kind {
|
let StatementKind::Assign(box (_, ref mut rhs)) = statement.kind else {
|
||||||
StatementKind::Assign(box (_, ref mut rhs)) => rhs,
|
span_bug!(
|
||||||
_ => {
|
statement.source_info.span,
|
||||||
span_bug!(
|
"{:?} is not an assignment",
|
||||||
statement.source_info.span,
|
statement
|
||||||
"{:?} is not an assignment",
|
);
|
||||||
statement
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -15,12 +15,9 @@ where
|
|||||||
L: HasLocalDecls<'tcx>,
|
L: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("is_disaligned({:?})", place);
|
debug!("is_disaligned({:?})", place);
|
||||||
let pack = match is_within_packed(tcx, local_decls, place) {
|
let Some(pack) = is_within_packed(tcx, local_decls, place) else {
|
||||||
None => {
|
debug!("is_disaligned({:?}) - not within packed", place);
|
||||||
debug!("is_disaligned({:?}) - not within packed", place);
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Some(pack) => pack,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = place.ty(local_decls, tcx).ty;
|
let ty = place.ty(local_decls, tcx).ty;
|
||||||
|
Loading…
Reference in New Issue
Block a user