address review

This commit is contained in:
b-naber 2022-06-02 19:42:29 +02:00
parent 5c95a3db2a
commit dbef6e4507
16 changed files with 80 additions and 93 deletions

View File

@ -358,7 +358,6 @@ dependencies = [
"libgit2-sys",
"log",
"memchr",
"num_cpus",
"opener",
"openssl",
"os_info",

View File

@ -140,6 +140,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
///
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
#[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
fn struct_generic(
&self,
tcx: TyCtxtAt<'tcx>,
@ -190,6 +191,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
decorate(err);
};
debug!("self.error: {:?}", self.error);
// Special handling for certain errors
match &self.error {
// Don't emit a new diagnostic for these errors

View File

@ -24,12 +24,6 @@ pub use fn_queries::*;
pub use machine::*;
pub(crate) use valtrees::{const_to_valtree_inner, valtree_to_const_value};
pub(crate) enum ValTreeCreationError {
NonSupportedType,
Other,
}
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
pub(crate) fn const_caller_location(
tcx: TyCtxt<'_>,
(file, line, col): (Symbol, u32, u32),
@ -44,6 +38,16 @@ pub(crate) fn const_caller_location(
ConstValue::Scalar(Scalar::from_maybe_pointer(loc_place.ptr, &tcx))
}
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;
pub(crate) enum ValTreeCreationError {
NodesOverflow,
NonSupportedType,
Other,
}
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
/// Evaluates a constant and turns it into a type-level constant value.
pub(crate) fn eval_to_valtree<'tcx>(
tcx: TyCtxt<'tcx>,
@ -62,11 +66,28 @@ pub(crate) fn eval_to_valtree<'tcx>(
let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
debug!(?place);
let valtree_result = const_to_valtree_inner(&ecx, &place);
let mut num_nodes = 0;
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
match valtree_result {
Ok(valtree) => Ok(Some(valtree)),
Err(_) => Ok(None),
Err(err) => {
let did = cid.instance.def_id();
let s = cid.display(tcx);
match err {
ValTreeCreationError::NodesOverflow => {
let msg = format!("maximum number of nodes exceeded in constant {}", &s);
let mut diag = match tcx.hir().span_if_local(did) {
Some(span) => tcx.sess.struct_span_err(span, &msg),
None => tcx.sess.struct_err(&msg),
};
diag.emit();
Ok(None)
}
ValTreeCreationError::NonSupportedType | ValTreeCreationError::Other => Ok(None),
}
}
}
}
@ -75,7 +96,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
pub(crate) fn try_destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
const_: ty::Const<'tcx>,
) -> Option<mir::DestructuredConst<'tcx>> {
) -> Option<ty::DestructuredConst<'tcx>> {
if let ty::ConstKind::Value(valtree) = const_.val() {
let branches = match valtree {
ty::ValTree::Branch(b) => b,
@ -141,7 +162,7 @@ pub(crate) fn try_destructure_const<'tcx>(
let fields = tcx.arena.alloc_from_iter(fields.into_iter());
Some(mir::DestructuredConst { variant, fields })
Some(ty::DestructuredConst { variant, fields })
} else {
None
}

View File

@ -1,6 +1,6 @@
use super::eval_queries::{mk_eval_cx, op_to_const};
use super::machine::CompileTimeEvalContext;
use super::{ValTreeCreationError, ValTreeCreationResult};
use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
@ -16,6 +16,7 @@ fn branches<'tcx>(
place: &MPlaceTy<'tcx>,
n: usize,
variant: Option<VariantIdx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
let place = match variant {
Some(variant) => ecx.mplace_downcast(&place, variant).unwrap(),
@ -27,7 +28,7 @@ fn branches<'tcx>(
let mut fields = Vec::with_capacity(n);
for i in 0..n {
let field = ecx.mplace_field(&place, i).unwrap();
let valtree = const_to_valtree_inner(ecx, &field)?;
let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
fields.push(Some(valtree));
}
@ -39,6 +40,11 @@ fn branches<'tcx>(
.collect::<Option<Vec<_>>>()
.expect("should have already checked for errors in ValTree creation");
// Have to account for ZSTs here
if branches.len() == 0 {
*num_nodes += 1;
}
Ok(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches)))
}
@ -46,6 +52,7 @@ fn branches<'tcx>(
fn slice_branches<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
let n = place
.len(&ecx.tcx.tcx)
@ -54,7 +61,7 @@ fn slice_branches<'tcx>(
let mut elems = Vec::with_capacity(n as usize);
for i in 0..n {
let place_elem = ecx.mplace_index(place, i).unwrap();
let valtree = const_to_valtree_inner(ecx, &place_elem)?;
let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?;
elems.push(valtree);
}
@ -65,12 +72,18 @@ fn slice_branches<'tcx>(
pub(crate) fn const_to_valtree_inner<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
let ty = place.layout.ty;
debug!("ty kind: {:?}", ty.kind());
if *num_nodes >= VALTREE_MAX_NODES {
return Err(ValTreeCreationError::NodesOverflow);
}
match ty.kind() {
ty::FnDef(..) => {
*num_nodes += 1;
Ok(ty::ValTree::zst())
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
@ -78,6 +91,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
return Err(ValTreeCreationError::Other);
};
let val = val.to_scalar().unwrap();
*num_nodes += 1;
Ok(ty::ValTree::Leaf(val.assert_int()))
}
@ -94,11 +108,11 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
};
debug!(?derefd_place);
const_to_valtree_inner(ecx, &derefd_place)
const_to_valtree_inner(ecx, &derefd_place, num_nodes)
}
ty::Str | ty::Slice(_) | ty::Array(_, _) => {
slice_branches(ecx, place)
slice_branches(ecx, place, num_nodes)
}
// Trait objects are not allowed in type level constants, as we have no concept for
// resolving their backing type, even if we can do that at const eval time. We may
@ -107,7 +121,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
ty::Tuple(elem_tys) => {
branches(ecx, place, elem_tys.len(), None)
branches(ecx, place, elem_tys.len(), None, num_nodes)
}
ty::Adt(def, _) => {
@ -120,7 +134,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
let Ok((_, variant)) = ecx.read_discriminant(&place.into()) else {
return Err(ValTreeCreationError::Other);
};
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant))
branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes)
}
ty::Never

View File

@ -194,7 +194,7 @@ impl<'tcx> TyCtxtAt<'tcx> {
impl<'tcx> TyCtxt<'tcx> {
/// Destructure a type-level constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
pub fn destructure_const(self, const_: ty::Const<'tcx>) -> mir::DestructuredConst<'tcx> {
pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
self.try_destructure_const(const_).unwrap()
}

View File

@ -78,7 +78,6 @@ impl<'tcx> ConstValue<'tcx> {
Some(self.try_to_scalar()?.assert_int())
}
#[inline(always)]
pub fn try_to_bits(&self, size: Size) -> Option<u128> {
self.try_to_scalar_int()?.to_bits(size).ok()
}

View File

@ -967,26 +967,26 @@ rustc_queries! {
query eval_to_valtree(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
) -> EvalToValTreeResult<'tcx> {
desc { "evaluate type-level constant" }
desc { "evaluating type-level constant" }
}
/// Converts a type level constant value into `ConstValue`
query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
desc { "convert type-level constant value to mir constant value"}
desc { "converting type-level constant value to mir constant value"}
}
/// Destructure a constant ADT or array into its variant index and its
/// field values or return `None` if constant is invalid.
///
/// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
query try_destructure_const(key: ty::Const<'tcx>) -> Option<mir::DestructuredConst<'tcx>> {
desc { "destructure type level constant"}
query try_destructure_const(key: ty::Const<'tcx>) -> Option<ty::DestructuredConst<'tcx>> {
desc { "destructuring type level constant"}
}
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
/// and its field values.
query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
desc { "destructure mir constant"}
desc { "destructuring mir constant"}
remap_env_constness
}
@ -995,7 +995,7 @@ rustc_queries! {
query deref_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "deref constant" }
desc { "dereferencing mir constant" }
remap_env_constness
}

View File

@ -42,8 +42,8 @@ use rustc_query_system::ich::StableHashingContext;
use rustc_session::cstore::CrateStoreDyn;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
pub use subst::*;
use rustc_target::abi::{Align, VariantIdx};
pub use vtable::*;
use std::fmt::Debug;
@ -2453,3 +2453,10 @@ pub struct FoundRelationships {
/// _>::AssocType = ?T`
pub output: bool,
}
/// The constituent parts of a type level constant of kind ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ty::Const<'tcx>],
}

View File

@ -98,6 +98,7 @@ pub trait Printer<'tcx>: Sized {
// Defaults (should not be overridden):
#[instrument(skip(self), level = "debug")]
fn default_print_def_path(
self,
def_id: DefId,

View File

@ -1460,9 +1460,7 @@ pub trait PrettyPrinter<'tcx>:
return Ok(self);
}
// Aggregates, printed as array/tuple/struct/variant construction syntax.
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..))
if !ty.has_param_types_or_consts() =>
{
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
let Some(contents) = self.tcx().try_destructure_const(
ty::Const::from_value(self.tcx(), valtree, ty)
) else {

View File

@ -1,9 +1,9 @@
use crate::build;
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 crate::thir::constant::parse_float_into_scalar;
use crate::thir::pattern::pat_from_hir;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@ -14,9 +14,7 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::*;
use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
use rustc_middle::ty::subst::Subst;
@ -24,7 +22,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::Symbol;
use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi;
use super::lints;
@ -1096,57 +1093,6 @@ fn parse_float_into_constval<'tcx>(
parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar)
}
#[instrument(skip(tcx, lit_input))]
pub(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_into_constval(*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))
}
///////////////////////////////////////////////////////////////////////////
// Builder methods are broken up into modules, depending on what kind
// of thing is being lowered. Note that they use the `unpack` macro

View File

@ -503,7 +503,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// deref pattern.
_ => {
if !pointee_ty.is_sized(tcx.at(span), param_env) {
// `tcx.deref_mirconstant()` below will ICE with an unsized type
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
if self.include_lint_checks {

View File

@ -14,7 +14,7 @@ impl Tr for str {
type Arr = [u8; 8];
#[cfg(cfail)]
type Arr = [u8; Self::C];
//[cfail]~^ ERROR cycle detected when evaluate type-level constant
//[cfail]~^ ERROR cycle detected when evaluating type-level constant
}
fn main() {}

View File

@ -1,4 +1,4 @@
error[E0391]: cycle detected when evaluate type-level constant
error[E0391]: cycle detected when evaluating type-level constant
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
@ -17,7 +17,7 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()]
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; _]`...
= note: ...which requires normalizing `[u8; _]`...
= note: ...which again requires evaluate type-level constant, completing the cycle
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/const-size_of-cycle.rs:3:1
|

View File

@ -4,7 +4,7 @@ use std::intrinsics;
struct Foo {
bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
//~^ ERROR cycle detected when evaluate type-level constant
//~^ ERROR cycle detected when evaluating type-level constant
x: usize,
}

View File

@ -1,4 +1,4 @@
error[E0391]: cycle detected when evaluate type-level constant
error[E0391]: cycle detected when evaluating type-level constant
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
@ -17,7 +17,7 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; _]`...
= note: ...which requires normalizing `[u8; _]`...
= note: ...which again requires evaluate type-level constant, completing the cycle
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/issue-44415.rs:5:1
|