Skip to content

Commit

Permalink
Auto merge of #111913 - oli-obk:valtrees2, r=lcnr
Browse files Browse the repository at this point in the history
Only rewrite valtree-constants to patterns and keep other constants opaque

Now that we can reliably fall back to comparing constants with `PartialEq::eq` to the match scrutinee, we can

1. eagerly try to convert constants to valtrees
2. then deeply convert the valtree to a pattern
3. if the to-valtree conversion failed, create an "opaque constant" pattern.

This PR specifically avoids any behavioral changes or major cleanups. What we can now do as follow ups is

* move the two remaining call sites to `destructure_mir_constant` off that query
* make valtree to pattern conversion infallible
    * this needs to be done after careful analysis of the effects. There may be user visible changes from that.

based on #111768
  • Loading branch information
bors committed May 31, 2023
2 parents ad8304a + 3c02cfc commit 871b595
Show file tree
Hide file tree
Showing 21 changed files with 302 additions and 325 deletions.
39 changes: 1 addition & 38 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

use crate::errors::MaxNumNodesInConstErr;
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
Scalar,
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, Scalar,
};
use rustc_hir::Mutability;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::{self, TyCtxt};
Expand Down Expand Up @@ -131,38 +129,3 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(

Ok(mir::DestructuredConstant { variant, fields })
}

#[instrument(skip(tcx), level = "debug")]
pub(crate) fn deref_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: mir::ConstantKind<'tcx>,
) -> mir::ConstantKind<'tcx> {
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.eval_mir_constant(&val, None, None).unwrap();
let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!(
tcx.global_alloc(alloc_id).unwrap_memory().0.0.mutability,
Mutability::Not,
"deref_mir_constant cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics",
);
}

let ty = match mplace.meta {
MemPlaceMeta::None => mplace.layout.ty,
// In case of unsized types, figure out the real type behind.
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
ty::Str => bug!("there's no sized equivalent of a `str`"),
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_target_usize(&tcx).unwrap()),
_ => bug!(
"type {} should not have metadata, but had {:?}",
mplace.layout.ty,
mplace.meta
),
},
};

mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty)
}
4 changes: 0 additions & 4 deletions compiler/rustc_const_eval/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ pub fn provide(providers: &mut Providers) {
providers.valtree_to_const_val = |tcx, (ty, valtree)| {
const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
};
providers.deref_mir_constant = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::deref_mir_constant(tcx, param_env, value)
};
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ where
/// Given the metadata, extract out the value at a particular index (if any).
#[inline(never)]
pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> T::Value<'tcx> {
debug!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size);
trace!("LazyTable::lookup: index={:?} len={:?}", i, self.encoded_size);

let start = self.position.get();
let bytes = &metadata.blob()[start..start + self.encoded_size];
Expand Down
47 changes: 1 addition & 46 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html

use crate::mir::interpret::{
AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, LitToConstInput, Scalar,
AllocRange, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use crate::mir::visit::MirVisitable;
use crate::ty::codec::{TyDecoder, TyEncoder};
Expand Down Expand Up @@ -2461,51 +2461,6 @@ impl<'tcx> ConstantKind<'tcx> {
Self::Val(val, ty)
}

#[instrument(skip(tcx), level = "debug", ret)]
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = match tcx.hir().get(hir_id) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def_id.to_def_id()),
"from_inline_const can only process anonymous constants"
),
};
let expr = &tcx.hir().body(body_id).value;
let ty = tcx.typeck(def_id).node_type(hir_id);

let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
hir::ExprKind::Lit(ref lit) => {
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None,
},
_ => None,
};
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
Ok(c) => return c,
Err(_) => {}
}
}

let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
let parent_substs =
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
let substs =
ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
.substs;

let uneval = UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None };
debug_assert!(!uneval.has_free_regions());

Self::Unevaluated(uneval, ty)
}

/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
/// converted to a constant, everything else becomes `Unevaluated`.
#[instrument(skip(tcx), level = "debug", ret)]
Expand Down
12 changes: 0 additions & 12 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1081,14 +1081,6 @@ rustc_queries! {
desc { "destructuring MIR constant"}
}

/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "dereferencing MIR constant" }
}

query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
desc { "getting a &core::panic::Location referring to a span" }
}
Expand All @@ -1100,10 +1092,6 @@ rustc_queries! {
desc { "converting literal to const" }
}

query lit_to_mir_constant(key: LitToConstInput<'tcx>) -> Result<mir::ConstantKind<'tcx>, LitToConstError> {
desc { "converting literal to mir constant" }
}

query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn as_constant_inner<'tcx>(
}

#[instrument(skip(tcx, lit_input))]
pub(crate) fn lit_to_mir_constant<'tcx>(
fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub(crate) use crate::build::expr::as_constant::lit_to_mir_constant;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use rustc_apfloat::ieee::{Double, Single};
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_mir_build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) {
providers.check_match = thir::pattern::check_match;
providers.lit_to_const = thir::constant::lit_to_const;
providers.lit_to_mir_constant = build::lit_to_mir_constant;
providers.mir_built = build::mir_built;
providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
providers.thir_body = thir::cx::thir_body;
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_mir_build/src/thir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
use rustc_span::DUMMY_SP;

use crate::build::parse_float_into_scalar;

pub(crate) fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
Expand Down Expand Up @@ -46,12 +48,28 @@ pub(crate) fn lit_to_const<'tcx>(
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ty::ValTree::from_scalar_int((*n).into())
}
(ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
{
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
let scalar_int =
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
let bits = parse_float_into_scalar(*n, *fty, neg)
.ok_or_else(|| {
LitToConstError::Reported(tcx.sess.delay_span_bug(
DUMMY_SP,
format!("couldn't parse float literal: {:?}", lit_input.lit),
))
})?
.assert_int();
ty::ValTree::from_scalar_int(bits)
}
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
(ast::LitKind::Err, _) => {
return Err(LitToConstError::Reported(
Expand Down
Loading

0 comments on commit 871b595

Please sign in to comment.