Skip to content

Use ValTree in all type level constants #83234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
@@ -57,15 +57,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> (Bx::Value, Ty<'tcx>) {
constant
.map(|val| {
let field_ty = ty.builtin_index().unwrap();
let c = ty::Const::from_value(bx.tcx(), val, ty);
let values: Vec<_> = bx
.tcx()
.destructure_const(ty::ParamEnv::reveal_all().and(&c))
.destructure_const(ty::ParamEnv::reveal_all().and((val, ty)))
.fields
.iter()
.map(|field| {
if let Some(prim) = field.val.try_to_scalar() {
.map(|(field, field_ty)| {
if let Some(prim) = field.try_to_scalar() {
let layout = bx.layout_of(field_ty);
let scalar = match layout.abi {
Abi::Scalar(ref x) => x,
@@ -78,7 +76,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
.collect();
let llval = bx.const_struct(&values, false);
(llval, c.ty)
(llval, ty)
})
.unwrap_or_else(|_| {
bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
9 changes: 9 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Item, ItemKind, Node};
use rustc_middle::dep_graph::DepContext;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{
self,
@@ -524,6 +525,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Err(NonTrivialPath)
}

fn print_const_value(
self,
_value: ConstValue<'tcx>,
_ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
Err(NonTrivialPath)
}

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
Ok(vec![self.tcx.crate_name(cnum).to_string()])
}
9 changes: 9 additions & 0 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
@@ -943,6 +944,14 @@ impl<'tcx> LateContext<'tcx> {
Ok(())
}

fn print_const_value(
self,
_val: ConstValue<'tcx>,
_ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
Ok(())
}

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
Ok(vec![self.tcx.crate_name(cnum)])
}
21 changes: 21 additions & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -2543,6 +2543,27 @@ impl ConstantKind<'tcx> {
}
}

#[inline]
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
pub fn eval_bits(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> u128 {
match self {
Self::Ty(ct) => ct.eval_bits(tcx, param_env, ty),
Self::Val(val, t) => {
assert_eq!(*t, ty);
let size = tcx
.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty))
.expect("could not normalize type")
.size;
val.try_to_scalar_int().unwrap().assert_bits(size)
}
}
}

#[inline]
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<bool> {
match self {
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/query.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ use smallvec::SmallVec;
use std::cell::Cell;
use std::fmt::{self, Debug};

use super::{Field, SourceInfo};
use super::{interpret::ConstValue, Field, SourceInfo};

#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
@@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [&'tcx ty::Const<'tcx>],
pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)],
}

/// Coverage information summarized from a MIR if instrumented for source code coverage (see
10 changes: 10 additions & 0 deletions compiler/rustc_middle/src/mir/type_foldable.rs
Original file line number Diff line number Diff line change
@@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
}
}
}

impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, _folder: &mut F) -> Self {
self
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
ControlFlow::CONTINUE
}
}
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -828,16 +828,16 @@ rustc_queries! {
/// Destructure a constant ADT or array into its variant index and its
/// field values.
query destructure_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> mir::DestructuredConst<'tcx> {
desc { "destructure constant" }
}

/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_const(
key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
) -> &'tcx ty::Const<'tcx> {
key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)>
) -> (ConstValue<'tcx>, Ty<'tcx>) {
desc { "deref constant" }
}

14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
};
use rustc_middle::ty::{ConstInt, ScalarInt};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -668,8 +669,9 @@ pub enum PatKind<'tcx> {

#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct PatRange<'tcx> {
pub lo: &'tcx ty::Const<'tcx>,
pub hi: &'tcx ty::Const<'tcx>,
pub lo: ScalarInt,
pub hi: ScalarInt,
pub ty: Ty<'tcx>,
pub end: RangeEnd,
}

@@ -788,10 +790,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
write!(f, "{}", subpattern)
}
PatKind::Constant { value } => write!(f, "{}", value),
PatKind::Range(PatRange { lo, hi, end }) => {
write!(f, "{}", lo)?;
PatKind::Range(PatRange { lo, hi, end, ty }) => {
let lo = ConstInt::new(lo, ty.is_signed(), ty.is_ptr_sized_integral());
let hi = ConstInt::new(hi, ty.is_signed(), ty.is_ptr_sized_integral());
write!(f, "{:?}", lo)?;
write!(f, "{}", end)?;
write!(f, "{}", hi)
write!(f, "{:?}", hi)
}
PatKind::Slice { ref prefix, ref slice, ref suffix }
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
17 changes: 17 additions & 0 deletions compiler/rustc_middle/src/ty/consts/int.rs
Original file line number Diff line number Diff line change
@@ -202,6 +202,23 @@ impl ScalarInt {
Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
}

#[inline]
pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
let i = i.into();
Self::try_from_uint(i, size)
.unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits()))
}

#[inline]
pub fn from_bool(b: bool) -> Self {
Self::from_uint(b as u8, Size::from_bytes(1))
}

#[inline]
pub fn from_char(c: char) -> Self {
Self::from_uint(c as u32, Size::from_bytes(4))
}

#[inline]
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
let data = i.into();
15 changes: 15 additions & 0 deletions compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::mir::interpret::ConstValue;
use crate::ty::subst::{GenericArg, Subst};
use crate::ty::{self, DefIdTree, Ty, TyCtxt};

@@ -68,6 +69,12 @@ pub trait Printer<'tcx>: Sized {

fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;

fn print_const_value(
self,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error>;

fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;

fn path_qualified(
@@ -362,3 +369,11 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
cx.print_const(self)
}
}

impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for (ConstValue<'tcx>, Ty<'tcx>) {
type Output = P::Const;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.print_const_value(self.0, self.1)
}
}
14 changes: 10 additions & 4 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -1200,10 +1200,8 @@ pub trait PrettyPrinter<'tcx>:
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
);
let contents =
self.tcx().destructure_const(ty::ParamEnv::reveal_all().and((ct, ty)));
let fields = contents.fields.iter().copied();

match *ty.kind() {
@@ -1458,6 +1456,14 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> {
self.pretty_print_const(ct, true)
}

fn print_const_value(
self,
val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> Result<Self::Const, Self::Error> {
self.pretty_print_const_value(val, ty, true)
}

fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.empty_path = true;
if cnum == LOCAL_CRATE {
23 changes: 14 additions & 9 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -546,7 +546,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
check_const_value_eq(relation, a_val, b_val, a, b)?
check_const_value_eq(relation, a_val, b_val, a.ty, b.ty)?
}

(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
@@ -585,10 +585,8 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
relation: &mut R,
a_val: ConstValue<'tcx>,
b_val: ConstValue<'tcx>,
// FIXME(oli-obk): these arguments should go away with valtrees
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
// FIXME(oli-obk): this should just be `bool` with valtrees
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
) -> RelateResult<'tcx, bool> {
let tcx = relation.tcx();
Ok(match (a_val, b_val) {
@@ -610,13 +608,20 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>(
}

(ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
let a_destructured = tcx.destructure_const(relation.param_env().and(a));
let b_destructured = tcx.destructure_const(relation.param_env().and(b));
let a_destructured = tcx.destructure_const(relation.param_env().and((a_val, a_ty)));
let b_destructured = tcx.destructure_const(relation.param_env().and((b_val, b_ty)));

// Both the variant and each field have to be equal.
if a_destructured.variant == b_destructured.variant {
for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
relation.consts(a_field, b_field)?;
for (&(a_val, a_ty), &(b_val, b_ty)) in
iter::zip(a_destructured.fields, b_destructured.fields)
{
let is_match = check_const_value_eq(relation, a_val, b_val, a_ty, b_ty)?;
if !is_match {
let a = ty::Const::from_value(relation.tcx(), a_val, a_ty);
let b = ty::Const::from_value(relation.tcx(), b_val, b_ty);
return Err(TypeError::ConstMismatch(expected_found(relation, a, b)));
}
}

true
32 changes: 16 additions & 16 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ use rustc_target::abi::{Integer, Size, TargetDataLayout};
use smallvec::SmallVec;
use std::{fmt, iter};

use super::ScalarInt;

#[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
/// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
@@ -616,40 +618,38 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
impl<'tcx> ty::TyS<'tcx> {
/// Returns the maximum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(std::char::MAX as u128),
ty::Char => Some(ScalarInt::from(std::char::MAX)),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
ty::FloatTy::F32 => ScalarInt::from(rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Returns the minimum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(0),
ty::Char => Some(ScalarInt::from('\0')),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
ty::FloatTy::F32 => ScalarInt::from(-::rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(-::rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Checks whether values of this type `T` are *moved* or *copied*
Loading