Auto merge of #94255 - b-naber:use-mir-constant-in-thir, r=oli-obk
Use mir constant in thir instead of ty::Const This is blocked on https://github.com/rust-lang/rust/pull/94059 (does include its changes, the first two commits in this PR correspond to those changes) and https://github.com/rust-lang/rust/pull/93800 being reinstated (which had to be reverted). Mainly opening since `@lcnr` offered to give some feedback and maybe also for a perf-run (if necessary). This currently contains a lot of duplication since some of the logic of `ty::Const` had to be copied to `mir::ConstantKind`, but with the introduction of valtrees a lot of that functionality will disappear from `ty::Const`. Only the last commit contains changes that need to be reviewed here. Did leave some `FIXME` comments regarding future implementation decisions and some things that might be incorrectly implemented. r? `@oli-obk`
This commit is contained in:
commit
e3c43e64ec
17 changed files with 227 additions and 55 deletions
|
@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
|
|||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_zero_sized(tcx.types.unit),
|
||||
literal: ConstantKind::zero_sized(tcx.types.unit),
|
||||
}))),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
use crate::build::Builder;
|
||||
use crate::thir::constant::parse_float;
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast as ast;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::interpret::{
|
||||
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
|
||||
};
|
||||
use rustc_middle::mir::interpret::Allocation;
|
||||
use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
|
@ -32,11 +31,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
ExprKind::Literal { lit, neg } => {
|
||||
let literal =
|
||||
match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
|
||||
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
|
||||
Err(LitToConstError::TypeError) => {
|
||||
bug!("encountered type error in `lit_to_constant")
|
||||
bug!("encountered type error in `lit_to_mir_constant")
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -90,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn lit_to_constant<'tcx>(
|
||||
#[instrument(skip(tcx, lit_input))]
|
||||
fn lit_to_mir_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
lit_input: LitToConstInput<'tcx>,
|
||||
) -> Result<ConstantKind<'tcx>, LitToConstError> {
|
||||
|
|
|
@ -322,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
|
||||
literal: ConstantKind::zero_sized(this.tcx.types.unit),
|
||||
}))))
|
||||
}
|
||||
ExprKind::Yield { .. }
|
||||
|
@ -552,7 +552,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||
let size = self.tcx.layout_of(param_ty).unwrap().size;
|
||||
let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
||||
let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
|
@ -563,7 +563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
|
||||
let n = 1 << (bits - 1);
|
||||
let literal = ty::Const::from_bits(self.tcx, n, param_ty);
|
||||
let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
);
|
||||
} else if let [success, fail] = *make_target_blocks(self) {
|
||||
assert_eq!(value.ty(), ty);
|
||||
let expect = self.literal_operand(test.span, value);
|
||||
let expect = self.literal_operand(test.span, value.into());
|
||||
let val = Operand::Copy(place);
|
||||
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
|
||||
} else {
|
||||
|
@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let target_blocks = make_target_blocks(self);
|
||||
|
||||
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
|
||||
let lo = self.literal_operand(test.span, lo);
|
||||
let hi = self.literal_operand(test.span, hi);
|
||||
let lo = self.literal_operand(test.span, lo.into());
|
||||
let hi = self.literal_operand(test.span, hi.into());
|
||||
let val = Operand::Copy(place);
|
||||
|
||||
let [success, fail] = *target_blocks else {
|
||||
|
@ -370,7 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
place: Place<'tcx>,
|
||||
mut ty: Ty<'tcx>,
|
||||
) {
|
||||
let mut expect = self.literal_operand(source_info.span, value);
|
||||
let mut expect = self.literal_operand(source_info.span, value.into());
|
||||
let mut val = Operand::Copy(place);
|
||||
|
||||
// If we're using `b"..."` as a pattern, we need to insert an
|
||||
|
@ -823,7 +823,7 @@ fn trait_method<'tcx>(
|
|||
method_name: Symbol,
|
||||
self_ty: Ty<'tcx>,
|
||||
params: &[GenericArg<'tcx>],
|
||||
) -> ty::Const<'tcx> {
|
||||
) -> ConstantKind<'tcx> {
|
||||
let substs = tcx.mk_substs_trait(self_ty, params);
|
||||
|
||||
// The unhygienic comparison here is acceptable because this is only
|
||||
|
@ -836,5 +836,6 @@ fn trait_method<'tcx>(
|
|||
|
||||
let method_ty = tcx.type_of(item.def_id);
|
||||
let method_ty = method_ty.subst(tcx, substs);
|
||||
ty::Const::zero_sized(tcx, method_ty)
|
||||
|
||||
ConstantKind::zero_sized(method_ty)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
use crate::build::Builder;
|
||||
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
@ -25,8 +26,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
/// Convenience function for creating a literal operand, one
|
||||
/// without any user type annotation.
|
||||
crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> {
|
||||
let literal = literal.into();
|
||||
crate fn literal_operand(
|
||||
&mut self,
|
||||
span: Span,
|
||||
literal: mir::ConstantKind<'tcx>,
|
||||
) -> Operand<'tcx> {
|
||||
let constant = Box::new(Constant { span, user_ty: None, literal });
|
||||
Operand::Constant(constant)
|
||||
}
|
||||
|
@ -34,7 +38,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
// Returns a zero literal operand for the appropriate type, works for
|
||||
// bool, char and integers.
|
||||
crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = ty::Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||
let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_middle::hir::place::Place as HirPlace;
|
|||
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
|
||||
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
|
||||
use rustc_middle::mir::{self, BinOp, BorrowKind, Field, UnOp};
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::adjustment::{
|
||||
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
|
||||
|
@ -491,7 +491,11 @@ impl<'tcx> Cx<'tcx> {
|
|||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
let anon_const_def_id =
|
||||
self.tcx.hir().local_def_id(anon_const.hir_id);
|
||||
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
|
||||
let value = mir::ConstantKind::from_anon_const(
|
||||
self.tcx,
|
||||
anon_const_def_id,
|
||||
self.param_env,
|
||||
);
|
||||
let span = self.tcx.hir().span(anon_const.hir_id);
|
||||
|
||||
InlineAsmOperand::Const { value, span }
|
||||
|
|
|
@ -55,7 +55,7 @@ use rustc_hir::{HirId, RangeEnd};
|
|||
use rustc_middle::mir::Field;
|
||||
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
|
||||
use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
@ -136,7 +136,7 @@ impl IntRange {
|
|||
fn from_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: Const<'tcx>,
|
||||
value: ty::Const<'tcx>,
|
||||
) -> Option<IntRange> {
|
||||
let ty = value.ty();
|
||||
if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
|
||||
|
@ -829,7 +829,8 @@ impl<'tcx> Constructor<'tcx> {
|
|||
}
|
||||
}
|
||||
(Str(self_val), Str(other_val)) => {
|
||||
// FIXME: there's probably a more direct way of comparing for equality
|
||||
// FIXME Once valtrees are available we can directly use the bytes
|
||||
// in the `Str` variant of the valtree for the comparison here.
|
||||
match compare_const_vals(
|
||||
pcx.cx.tcx,
|
||||
*self_val,
|
||||
|
|
|
@ -488,9 +488,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
|
||||
Ok(value) => {
|
||||
let const_ =
|
||||
ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
|
||||
|
||||
let const_ = ty::Const::from_value(self.tcx, value, ty);
|
||||
let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
|
||||
|
||||
if !is_associated_const {
|
||||
|
@ -585,7 +583,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
let lit_input =
|
||||
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
|
||||
match self.tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
|
||||
Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
|
||||
Err(LitToConstError::Reported) => PatKind::Wild,
|
||||
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
|
||||
}
|
||||
|
@ -739,6 +737,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
crate fn compare_const_vals<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
a: ty::Const<'tcx>,
|
||||
|
@ -746,8 +745,6 @@ crate fn compare_const_vals<'tcx>(
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ordering> {
|
||||
trace!("compare_const_vals: {:?}, {:?}", a, b);
|
||||
|
||||
let from_bool = |v: bool| v.then_some(Ordering::Equal);
|
||||
|
||||
let fallback = || from_bool(a == b);
|
||||
|
|
|
@ -765,10 +765,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
|
|||
/// `is_under_guard` is used to inform if the pattern has a guard. If it
|
||||
/// has one it must not be inserted into the matrix. This shouldn't be
|
||||
/// relied on for soundness.
|
||||
#[instrument(
|
||||
level = "debug",
|
||||
skip(cx, matrix, witness_preference, hir_id, is_under_guard, is_top_level)
|
||||
)]
|
||||
#[instrument(level = "debug", skip(cx, matrix, hir_id))]
|
||||
fn is_useful<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
matrix: &Matrix<'p, 'tcx>,
|
||||
|
@ -800,6 +797,7 @@ fn is_useful<'p, 'tcx>(
|
|||
|
||||
let ty = v.head().ty();
|
||||
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
|
||||
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
|
||||
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
|
||||
|
||||
// If the first pattern is an or-pattern, expand it.
|
||||
|
@ -809,9 +807,11 @@ fn is_useful<'p, 'tcx>(
|
|||
// We try each or-pattern branch in turn.
|
||||
let mut matrix = matrix.clone();
|
||||
for v in v.expand_or_pat() {
|
||||
debug!(?v);
|
||||
let usefulness = ensure_sufficient_stack(|| {
|
||||
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
|
||||
});
|
||||
debug!(?usefulness);
|
||||
ret.extend(usefulness);
|
||||
// If pattern has a guard don't add it to the matrix.
|
||||
if !is_under_guard {
|
||||
|
@ -822,6 +822,7 @@ fn is_useful<'p, 'tcx>(
|
|||
}
|
||||
} else {
|
||||
let v_ctor = v.head().ctor();
|
||||
debug!(?v_ctor);
|
||||
if let Constructor::IntRange(ctor_range) = &v_ctor {
|
||||
// Lint on likely incorrect range patterns (#63987)
|
||||
ctor_range.lint_overlapping_range_endpoints(
|
||||
|
@ -895,7 +896,7 @@ fn is_useful<'p, 'tcx>(
|
|||
}
|
||||
|
||||
/// The arm of a match expression.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
crate struct MatchArm<'p, 'tcx> {
|
||||
/// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
|
||||
crate pat: &'p DeconstructedPat<'p, 'tcx>,
|
||||
|
@ -928,6 +929,7 @@ crate struct UsefulnessReport<'p, 'tcx> {
|
|||
///
|
||||
/// Note: the input patterns must have been lowered through
|
||||
/// `check_match::MatchVisitor::lower_pattern`.
|
||||
#[instrument(skip(cx, arms), level = "debug")]
|
||||
crate fn compute_match_usefulness<'p, 'tcx>(
|
||||
cx: &MatchCheckCtxt<'p, 'tcx>,
|
||||
arms: &[MatchArm<'p, 'tcx>],
|
||||
|
@ -939,6 +941,7 @@ crate fn compute_match_usefulness<'p, 'tcx>(
|
|||
.iter()
|
||||
.copied()
|
||||
.map(|arm| {
|
||||
debug!(?arm);
|
||||
let v = PatStack::from_pattern(arm.pat);
|
||||
is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true);
|
||||
if !arm.has_guard {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue