1
Fork 0

rebase and use ty::Const in patterns again

This commit is contained in:
b-naber 2022-03-25 10:06:10 +01:00
parent ac60db231c
commit 0078e54185
13 changed files with 73 additions and 144 deletions

View file

@ -184,13 +184,13 @@ pub(crate) fn destructure_mir_constant<'tcx>(
// We go to `usize` as we cannot allocate anything bigger anyway. // We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match val.ty().kind() { let (field_count, variant, down) = match val.ty().kind() {
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
ty::Adt(def, _) if def.variants.is_empty() => { ty::Adt(def, _) if def.variants().is_empty() => {
return mir::DestructuredMirConstant { variant: None, fields: &[] }; return mir::DestructuredMirConstant { variant: None, fields: &[] };
} }
ty::Adt(def, _) => { ty::Adt(def, _) => {
let variant = ecx.read_discriminant(&op).unwrap().1; let variant = ecx.read_discriminant(&op).unwrap().1;
let down = ecx.operand_downcast(&op, variant).unwrap(); let down = ecx.operand_downcast(&op, variant).unwrap();
(def.variants[variant].fields.len(), Some(variant), down) (def.variants()[variant].fields.len(), Some(variant), down)
} }
ty::Tuple(substs) => (substs.len(), None, op), ty::Tuple(substs) => (substs.len(), None, op),
_ => bug!("cannot destructure constant {:?}", val), _ => bug!("cannot destructure constant {:?}", val),
@ -253,7 +253,7 @@ pub(crate) fn deref_mir_constant<'tcx>(
let mplace = ecx.deref_operand(&op).unwrap(); let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance { if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!( assert_eq!(
tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability, tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
Mutability::Not, Mutability::Not,
"deref_const cannot be used with mutable allocations as \ "deref_const cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics", that could allow pattern matching to observe mutable statics",

View file

@ -2711,7 +2711,7 @@ impl<'tcx> ConstantKind<'tcx> {
if let Some(val) = c.val().try_eval(tcx, param_env) { if let Some(val) = c.val().try_eval(tcx, param_env) {
match val { match val {
Ok(val) => Self::Val(val, c.ty()), Ok(val) => Self::Val(val, c.ty()),
Err(ErrorReported) => Self::Ty(tcx.const_error(self.ty())), Err(_) => Self::Ty(tcx.const_error(self.ty())),
} }
} else { } else {
self self

View file

@ -193,7 +193,7 @@ pub enum StmtKind<'tcx> {
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Expr<'_>, 144); rustc_data_structures::static_assert_size!(Expr<'_>, 104);
/// A THIR expression. /// A THIR expression.
#[derive(Debug, HashStable)] #[derive(Debug, HashStable)]
@ -736,11 +736,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
Some(adt_def.variant(variant_index)) Some(adt_def.variant(variant_index))
} }
_ => self.ty.ty_adt_def().and_then(|adt| { _ => self.ty.ty_adt_def().and_then(|adt| {
if !adt.is_enum() { if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
Some(adt.non_enum_variant())
} else {
None
}
}), }),
}; };

View file

@ -2,7 +2,6 @@ use super::{
Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
}; };
use crate::mir::ConstantKind; use crate::mir::ConstantKind;
use crate::ty::Const;
pub trait Visitor<'a, 'tcx: 'a>: Sized { pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn thir(&self) -> &'a Thir<'tcx>; fn thir(&self) -> &'a Thir<'tcx>;

View file

@ -76,11 +76,7 @@ static_assert_size!(ConstKind<'_>, 40);
impl<'tcx> ConstKind<'tcx> { impl<'tcx> ConstKind<'tcx> {
#[inline] #[inline]
pub fn try_to_value(self) -> Option<ConstValue<'tcx>> { pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
if let ConstKind::Value(val) = self { if let ConstKind::Value(val) = self { Some(val) } else { None }
Some(val)
} else {
None
}
} }
#[inline] #[inline]

View file

@ -1,17 +1,12 @@
//! See docs in build/expr/mod.rs //! See docs in build/expr/mod.rs
use crate::build::Builder; use crate::build::Builder;
use crate::thir::constant::parse_float;
use rustc_ast::ast;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::thir::*; use rustc_middle::thir::*;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
use rustc_target::abi::Size;
impl<'a, 'tcx> Builder<'a, 'tcx> { impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that /// Compile `expr`, yielding a compile-time constant. Assumes that
@ -32,11 +27,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
ExprKind::Literal { lit, neg } => { ExprKind::Literal { lit, neg } => {
let literal = let literal =
match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { match tcx.lit_to_mir_constant(LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c, Ok(c) => c,
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)), Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
Err(LitToConstError::TypeError) => { Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_constant") bug!("encountered type error in `lit_to_mir_constant")
} }
}; };
@ -85,60 +80,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant { span, user_ty: None, literal } Constant { span, user_ty: None, literal }
} }
ExprKind::ConstBlock { value } => {
Constant { span: span, user_ty: None, literal: value }
}
_ => span_bug!(span, "expression is not a valid constant {:?}", kind), _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
} }
} }
} }
crate fn lit_to_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
let param_ty = ty::ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
};
let value = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
Ok(ConstantKind::Val(value, ty))
}

View file

@ -59,6 +59,56 @@ crate fn lit_to_const<'tcx>(
Ok(ty::Const::from_value(tcx, lit, ty)) Ok(ty::Const::from_value(tcx, lit, ty))
} }
crate fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
let param_ty = ty::ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
};
let value = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
Ok(ConstantKind::Val(value, ty))
}
// FIXME move this to rustc_mir_build::build // FIXME move this to rustc_mir_build::build
pub(crate) fn parse_float<'tcx>( pub(crate) fn parse_float<'tcx>(
num: Symbol, num: Symbol,

View file

@ -5,6 +5,7 @@
use crate::thir::pattern::pat_from_hir; use crate::thir::pattern::pat_from_hir;
use crate::thir::util::UserAnnotatedTyHelpers; use crate::thir::util::UserAnnotatedTyHelpers;
use rustc_ast::ast;
use rustc_data_structures::steal::Steal; use rustc_data_structures::steal::Steal;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir; use rustc_hir as hir;
@ -15,7 +16,7 @@ use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::mir::ConstantKind; use rustc_middle::mir::ConstantKind;
use rustc_middle::thir::*; use rustc_middle::thir::*;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span; use rustc_span::Span;
crate fn thir_body<'tcx>( crate fn thir_body<'tcx>(

View file

@ -377,10 +377,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
} }
} }
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
self.is_poly |= ct.has_param_types_or_consts();
}
fn visit_constant(&mut self, ct: mir::ConstantKind<'tcx>) { fn visit_constant(&mut self, ct: mir::ConstantKind<'tcx>) {
self.is_poly |= ct.has_param_types_or_consts(); self.is_poly |= ct.has_param_types_or_consts();
} }
@ -815,51 +811,3 @@ impl<'tcx> ConstUnifyCtxt<'tcx> {
} }
} }
} }
/* Think I need these changes
=======
match (a_ct, b_ct) {
(mir::ConstantKind::Ty(a_ct), mir::ConstantKind::Ty(b_ct)) => {
match (a_ct.val(), b_ct.val()) {
// We can just unify errors with everything to reduce the amount of
// emitted errors here.
(ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
(ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
a_param == b_param
}
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
a_val == b_val
}
// If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
// we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
// means that we only allow inference variables if they are equal.
(ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => {
a_val == b_val
}
// We expand generic anonymous constants at the start of this function, so this
// branch should only be taking when dealing with associated constants, at
// which point directly comparing them seems like the desired behavior.
//
// FIXME(generic_const_exprs): This isn't actually the case.
// We also take this branch for concrete anonymous constants and
// expand generic anonymous constants with concrete substs.
(ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
a_uv == b_uv
}
// FIXME(generic_const_exprs): We may want to either actually try
// to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
// this, for now we just return false here.
_ => false,
}
}
(mir::ConstantKind::Val(a_val, a_ty), mir::ConstantKind::Val(b_val, b_ty)) => {
a_val == b_val && a_ty == b_ty
}
_ => {
// FIXME Can it happen that we need to compare ConstantKind::Ty(ConstKind::Value)
// with a ConstantKind::Val and vice versa?
false
>>>>>>> 6064f16d846 (change thir to use mir::ConstantKind instead of ty::Const)
*/

View file

@ -407,7 +407,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
let pred = let pred =
ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
ProcessResult::Changed(mk_pending(vec![ ProcessResult::Changed(mk_pending(vec![
obligation.with(pred.to_predicate(self.selcx.tcx())) obligation.with(pred.to_predicate(self.selcx.tcx())),
])) ]))
} }
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {

View file

@ -1,4 +1,4 @@
use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt}; use clippy_utils::consts::{constant, constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_note; use clippy_utils::diagnostics::span_lint_and_note;
use core::cmp::Ordering; use core::cmp::Ordering;
use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@ -32,18 +32,15 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
.filter_map(|arm| { .filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm { if let Arm { pat, guard: None, .. } = *arm {
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
let lhs_const = match lhs { let lhs_val = match lhs {
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0.int_value(cx, ty)?,
None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?, None => FullInt::U(ty.numeric_min_val(cx.tcx)?),
}; };
let rhs_const = match rhs { let rhs_val = match rhs {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0.int_value(cx, ty)?,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, None => FullInt::U(ty.numeric_max_val(cx.tcx)?),
}; };
let lhs_val = lhs_const.int_value(cx, ty)?;
let rhs_val = rhs_const.int_value(cx, ty)?;
let rhs_bound = match range_end { let rhs_bound = match range_end {
RangeEnd::Included => EndBound::Included(rhs_val), RangeEnd::Included => EndBound::Included(rhs_val),
RangeEnd::Excluded => EndBound::Excluded(rhs_val), RangeEnd::Excluded => EndBound::Excluded(rhs_val),

View file

@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
if_chain! { if_chain! {
if let ExprKind::Lit(ref l) = lit.kind; if let ExprKind::Lit(ref l) = lit.kind;
if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
if cx.typeck_results().expr_ty(exp).is_integral(); if cx.typeck_results().expr_ty(exp).is_integral();
then { then {

View file

@ -179,7 +179,7 @@ impl Constant {
} }
/// Parses a `LitKind` to a `Constant`. /// Parses a `LitKind` to a `Constant`.
pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
match *lit { match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)), LitKind::Byte(b) => Constant::Int(u128::from(b)),
@ -301,7 +301,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, "cfg").is_some() {
None None
} else { } else {
Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))) Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
} }
}, },
ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec), ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),