mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
address review
This commit is contained in:
parent
5c95a3db2a
commit
dbef6e4507
@ -358,7 +358,6 @@ dependencies = [
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"memchr",
|
||||
"num_cpus",
|
||||
"opener",
|
||||
"openssl",
|
||||
"os_info",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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>],
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user