Promote Ref
s to constants instead of static
This commit is contained in:
parent
a59abfa450
commit
1688719214
53 changed files with 447 additions and 223 deletions
|
@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
promoted: Option<mir::Promoted>,
|
||||
span: Option<Span>,
|
||||
) -> ConstEvalResult<'tcx> {
|
||||
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
|
||||
if let Some(instance) = instance {
|
||||
if let Some(promoted) = promoted {
|
||||
self.const_eval_promoted(instance, promoted)
|
||||
} else {
|
||||
self.const_eval_instance(param_env, instance, span)
|
||||
}
|
||||
} else {
|
||||
Err(ErrorHandled::TooGeneric)
|
||||
}
|
||||
|
|
|
@ -166,6 +166,16 @@ pub struct Body<'tcx> {
|
|||
|
||||
/// A span representing this MIR, for error reporting.
|
||||
pub span: Span,
|
||||
|
||||
/// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
|
||||
/// we'd statically know that no thing with interior mutability will ever be available to the
|
||||
/// user without some serious unsafe code. Now this means that our promoted is actually
|
||||
/// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
|
||||
/// index may be a runtime value. Such a promoted value is illegal because it has reachable
|
||||
/// interior mutability. This flag just makes this situation very obvious where the previous
|
||||
/// implementation without the flag hid this situation silently.
|
||||
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
|
||||
pub ignore_interior_mut_in_const_validation: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> Body<'tcx> {
|
||||
|
@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> {
|
|||
spread_arg: None,
|
||||
var_debug_info,
|
||||
span,
|
||||
ignore_interior_mut_in_const_validation: false,
|
||||
control_flow_destroyed,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -515,6 +515,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
|
|||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
None,
|
||||
Some(obligation.cause.span),
|
||||
) {
|
||||
Ok(_) => ProcessResult::Changed(vec![]),
|
||||
|
|
|
@ -802,8 +802,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
if !(obligation.param_env, substs).has_local_value() {
|
||||
match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None)
|
||||
{
|
||||
match self.tcx().const_eval_resolve(
|
||||
obligation.param_env,
|
||||
def_id,
|
||||
substs,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
|
|
|
@ -359,7 +359,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
|
|||
/// Pushes the obligations required for an array length to be WF
|
||||
/// into `self.out`.
|
||||
fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
|
||||
assert!(promoted.is_none());
|
||||
|
||||
let obligations = self.nominal_obligations(def_id, substs);
|
||||
self.out.extend(obligations);
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ impl FlagComputation {
|
|||
fn add_const(&mut self, c: &ty::Const<'_>) {
|
||||
self.add_ty(c.ty);
|
||||
match c.val {
|
||||
ty::ConstKind::Unevaluated(_, substs) => {
|
||||
ty::ConstKind::Unevaluated(_, substs, _) => {
|
||||
self.add_substs(substs);
|
||||
self.add_flags(TypeFlags::HAS_PROJECTION);
|
||||
}
|
||||
|
|
|
@ -841,14 +841,20 @@ pub trait PrettyPrinter<'tcx>:
|
|||
|
||||
match (ct.val, &ct.ty.kind) {
|
||||
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
|
||||
(ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) {
|
||||
Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {
|
||||
p!(print_value_path(did, substs))
|
||||
}
|
||||
(ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
|
||||
if let Some(promoted) = promoted {
|
||||
p!(print_value_path(did, substs));
|
||||
p!(write("::{:?}", promoted));
|
||||
} else {
|
||||
match self.tcx().def_kind(did) {
|
||||
Some(DefKind::Static)
|
||||
| Some(DefKind::Const)
|
||||
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
|
||||
_ => {
|
||||
if did.is_local() {
|
||||
let span = self.tcx().def_span(did);
|
||||
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
|
||||
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
|
||||
{
|
||||
p!(write("{}", snip))
|
||||
} else {
|
||||
p!(write("_: "), print(ct.ty))
|
||||
|
@ -857,7 +863,9 @@ pub trait PrettyPrinter<'tcx>:
|
|||
p!(write("_: "), print(ct.ty))
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),
|
||||
(ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
|
||||
(ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty),
|
||||
|
|
|
@ -568,12 +568,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
|
|||
|
||||
// FIXME(const_generics): this is wrong, as it is a projection
|
||||
(
|
||||
ty::ConstKind::Unevaluated(a_def_id, a_substs),
|
||||
ty::ConstKind::Unevaluated(b_def_id, b_substs),
|
||||
) if a_def_id == b_def_id => {
|
||||
ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
|
||||
ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
|
||||
) if a_def_id == b_def_id && a_promoted == b_promoted => {
|
||||
let substs =
|
||||
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
|
||||
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
|
||||
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
|
||||
}
|
||||
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
|
||||
};
|
||||
|
|
|
@ -1037,8 +1037,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
|
|||
match *self {
|
||||
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
|
||||
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
|
||||
ty::ConstKind::Unevaluated(did, substs) => {
|
||||
ty::ConstKind::Unevaluated(did, substs.fold_with(folder))
|
||||
ty::ConstKind::Unevaluated(did, substs, promoted) => {
|
||||
ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
|
||||
}
|
||||
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
|
||||
*self
|
||||
|
@ -1050,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
|
|||
match *self {
|
||||
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
|
||||
ty::ConstKind::Param(p) => p.visit_with(visitor),
|
||||
ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
|
||||
ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
|
||||
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::infer::canonical::Canonical;
|
|||
use crate::middle::region;
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::mir::interpret::Scalar;
|
||||
use crate::mir::Promoted;
|
||||
use crate::ty::layout::VariantIdx;
|
||||
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
|
||||
|
@ -2375,7 +2376,7 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
|
||||
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
|
||||
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
|
||||
let param_env_and_substs = param_env.with_reveal_all().and(substs);
|
||||
|
||||
// Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
|
||||
|
@ -2387,11 +2388,11 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
// try to resolve e.g. associated constants to their definition on an impl, and then
|
||||
// evaluate the const.
|
||||
tcx.const_eval_resolve(param_env, did, substs, None).ok()
|
||||
tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok()
|
||||
};
|
||||
|
||||
match self.val {
|
||||
ConstKind::Unevaluated(did, substs) => {
|
||||
ConstKind::Unevaluated(did, substs, promoted) => {
|
||||
// HACK(eddyb) when substs contain e.g. inference variables,
|
||||
// attempt using identity substs instead, that will succeed
|
||||
// when the expression doesn't depend on any parameters.
|
||||
|
@ -2401,12 +2402,12 @@ impl<'tcx> Const<'tcx> {
|
|||
let identity_substs = InternalSubsts::identity_for_item(tcx, did);
|
||||
// The `ParamEnv` needs to match the `identity_substs`.
|
||||
let identity_param_env = tcx.param_env(did);
|
||||
match try_const_eval(did, identity_param_env, identity_substs) {
|
||||
match try_const_eval(did, identity_param_env, identity_substs, promoted) {
|
||||
Some(ct) => ct.subst(tcx, substs),
|
||||
None => self,
|
||||
}
|
||||
} else {
|
||||
try_const_eval(did, param_env, substs).unwrap_or(self)
|
||||
try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
|
||||
}
|
||||
}
|
||||
_ => self,
|
||||
|
@ -2470,7 +2471,7 @@ pub enum ConstKind<'tcx> {
|
|||
|
||||
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
|
||||
/// variants when the code is monomorphic enough for that.
|
||||
Unevaluated(DefId, SubstsRef<'tcx>),
|
||||
Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
|
||||
|
||||
/// Used to hold computed value.
|
||||
Value(ConstValue<'tcx>),
|
||||
|
|
|
@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
|
|||
| ty::Bound(..)
|
||||
| ty::Foreign(..) => {}
|
||||
ty::Array(ty, len) => {
|
||||
if let ty::ConstKind::Unevaluated(_, substs) = len.val {
|
||||
if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
|
||||
assert!(promoted.is_none());
|
||||
stack.extend(substs.types().rev());
|
||||
}
|
||||
stack.push(len.ty);
|
||||
|
|
|
@ -20,7 +20,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// use `get_static` to get at their id.
|
||||
// FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
|
||||
// always produce `&STATIC`. This may also simplify how const eval works with statics.
|
||||
ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => {
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted)
|
||||
if self.cx.tcx().is_static(def_id) =>
|
||||
{
|
||||
assert!(promoted.is_none());
|
||||
assert!(substs.is_empty(), "we don't support generic statics yet");
|
||||
let static_ = bx.get_static(def_id);
|
||||
// we treat operands referring to statics as if they were `&STATIC` instead
|
||||
|
@ -40,11 +43,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
|
||||
match constant.literal.val {
|
||||
ty::ConstKind::Unevaluated(def_id, substs) => {
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
let substs = self.monomorphize(&substs);
|
||||
self.cx
|
||||
.tcx()
|
||||
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
|
||||
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
|
||||
.map_err(|err| {
|
||||
self.cx
|
||||
.tcx()
|
||||
|
|
|
@ -310,7 +310,37 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
|
||||
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
|
||||
if let Some(promoted) = promoted {
|
||||
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
|
||||
promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
|
||||
ty,
|
||||
san_ty| {
|
||||
if let Err(terr) = verifier.cx.eq_types(
|
||||
san_ty,
|
||||
ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
verifier,
|
||||
promoted,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
san_ty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
if !self.errors_reported {
|
||||
let promoted_body = self.promoted[promoted];
|
||||
self.sanitize_promoted(promoted_body, location);
|
||||
|
||||
let promoted_ty = promoted_body.return_ty();
|
||||
check_err(self, &promoted_body, ty, promoted_ty);
|
||||
}
|
||||
} else {
|
||||
if let Err(terr) = self.cx.fully_perform_op(
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
|
@ -320,7 +350,14 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
UserSubsts { substs, user_self_ty: None },
|
||||
)),
|
||||
) {
|
||||
span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
|
||||
span_mirbug!(
|
||||
self,
|
||||
constant,
|
||||
"bad constant type {:?} ({:?})",
|
||||
constant,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
|
||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
|
|||
|
||||
let loc_ty = tcx.caller_location_ty();
|
||||
let loc_place = ecx.alloc_caller_location(file, line, col);
|
||||
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
|
||||
intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
|
||||
let loc_const = ty::Const {
|
||||
ty: loc_ty,
|
||||
val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),
|
||||
|
|
|
@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
|
|||
ecx.run()?;
|
||||
|
||||
// Intern the result
|
||||
intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
|
||||
intern_const_alloc_recursive(
|
||||
ecx,
|
||||
tcx.static_mutability(cid.instance.def_id()),
|
||||
ret,
|
||||
body.ignore_interior_mut_in_const_validation,
|
||||
)?;
|
||||
|
||||
debug!("eval_body_using_ecx done: {:?}", *ret);
|
||||
Ok(ret)
|
||||
|
@ -171,10 +176,15 @@ fn validate_and_turn_into_const<'tcx>(
|
|||
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
|
||||
let val = (|| {
|
||||
let mplace = ecx.raw_const_to_mplace(constant)?;
|
||||
|
||||
// FIXME do not validate promoteds until a decision on
|
||||
// https://github.com/rust-lang/rust/issues/67465 is made
|
||||
if cid.promoted.is_none() {
|
||||
let mut ref_tracking = RefTracking::new(mplace);
|
||||
while let Some((mplace, path)) = ref_tracking.todo.pop() {
|
||||
ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
|
||||
}
|
||||
}
|
||||
// Now that we validated, turn this into a proper constant.
|
||||
// Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides
|
||||
// whether they become immediates.
|
||||
|
|
|
@ -411,12 +411,15 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
|||
let def_id = cx.tcx.hir().local_def_id(count.hir_id);
|
||||
let substs = InternalSubsts::identity_for_item(cx.tcx, def_id);
|
||||
let span = cx.tcx.def_span(def_id);
|
||||
let count = match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, Some(span)) {
|
||||
let count =
|
||||
match cx.tcx.const_eval_resolve(cx.param_env, def_id, substs, None, Some(span)) {
|
||||
Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env),
|
||||
Err(ErrorHandled::Reported) => 0,
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
let span = cx.tcx.def_span(def_id);
|
||||
cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters");
|
||||
cx.tcx
|
||||
.sess
|
||||
.span_err(span, "array lengths can't depend on generic parameters");
|
||||
0
|
||||
}
|
||||
};
|
||||
|
@ -523,7 +526,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
|||
// and not the beginning of discriminants (which is always `0`)
|
||||
let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
|
||||
let lhs = mk_const(cx.tcx().mk_const(ty::Const {
|
||||
val: ty::ConstKind::Unevaluated(did, substs),
|
||||
val: ty::ConstKind::Unevaluated(did, substs, None),
|
||||
ty: var_ty,
|
||||
}));
|
||||
let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
|
||||
|
@ -719,7 +722,7 @@ fn convert_path_expr<'a, 'tcx>(
|
|||
debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
|
||||
ExprKind::Literal {
|
||||
literal: cx.tcx.mk_const(ty::Const {
|
||||
val: ty::ConstKind::Unevaluated(def_id, substs),
|
||||
val: ty::ConstKind::Unevaluated(def_id, substs, None),
|
||||
ty: cx.tables().node_type(expr.hir_id),
|
||||
}),
|
||||
user_ty,
|
||||
|
|
|
@ -749,6 +749,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
self.param_env.with_reveal_all(),
|
||||
def_id,
|
||||
substs,
|
||||
None,
|
||||
Some(span),
|
||||
) {
|
||||
Ok(value) => {
|
||||
|
|
|
@ -41,6 +41,11 @@ struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> {
|
|||
/// despite the nested mutable reference!
|
||||
/// The field gets updated when an `UnsafeCell` is encountered.
|
||||
mutability: Mutability,
|
||||
|
||||
/// This flag is to avoid triggering UnsafeCells are not allowed behind references in constants
|
||||
/// for promoteds.
|
||||
/// It's a copy of `mir::Body`'s ignore_interior_mut_in_const_validation field
|
||||
ignore_interior_mut_in_const_validation: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
|
||||
|
@ -164,14 +169,16 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx
|
|||
// References we encounter inside here are interned as pointing to mutable
|
||||
// allocations.
|
||||
let old = std::mem::replace(&mut self.mutability, Mutability::Mut);
|
||||
if !self.ignore_interior_mut_in_const_validation {
|
||||
assert_ne!(
|
||||
self.mode,
|
||||
InternMode::Const,
|
||||
"UnsafeCells are not allowed behind references in constants. This should have \
|
||||
been prevented statically by const qualification. If this were allowed one \
|
||||
would be able to change a constant at one use site and other use sites could \
|
||||
observe that mutation.",
|
||||
"UnsafeCells are not allowed behind references in constants. This should \
|
||||
have been prevented statically by const qualification. If this were \
|
||||
allowed one would be able to change a constant at one use site and other \
|
||||
use sites could observe that mutation.",
|
||||
);
|
||||
}
|
||||
let walked = self.walk_aggregate(mplace, fields);
|
||||
self.mutability = old;
|
||||
return walked;
|
||||
|
@ -266,6 +273,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
// The `mutability` of the place, ignoring the type.
|
||||
place_mut: Option<hir::Mutability>,
|
||||
ret: MPlaceTy<'tcx>,
|
||||
ignore_interior_mut_in_const_validation: bool,
|
||||
) -> InterpResult<'tcx> {
|
||||
let tcx = ecx.tcx;
|
||||
let (base_mutability, base_intern_mode) = match place_mut {
|
||||
|
@ -302,6 +310,7 @@ pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx>>(
|
|||
mode,
|
||||
leftover_allocations,
|
||||
mutability,
|
||||
ignore_interior_mut_in_const_validation,
|
||||
}
|
||||
.visit_value(mplace);
|
||||
if let Err(error) = interned {
|
||||
|
|
|
@ -532,7 +532,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Early-return cases.
|
||||
let val_val = match val.val {
|
||||
ty::ConstKind::Param(_) => throw_inval!(TooGeneric),
|
||||
ty::ConstKind::Unevaluated(def_id, substs) => {
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
// We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation.
|
||||
// The reason we use `const_eval_raw` everywhere else is to prevent cycles during
|
||||
|
|
|
@ -1249,8 +1249,8 @@ fn collect_const<'tcx>(
|
|||
collect_miri(tcx, id, output);
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Unevaluated(def_id, substs) => {
|
||||
match tcx.const_eval_resolve(param_env, def_id, substs, None) {
|
||||
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
|
||||
match tcx.const_eval_resolve(param_env, def_id, substs, promoted, None) {
|
||||
Ok(val) => collect_const(tcx, val, param_substs, output),
|
||||
Err(ErrorHandled::Reported) => {}
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
|
|
|
@ -102,7 +102,9 @@ pub trait Qualif {
|
|||
// Note: this uses `constant.literal.ty` which is a reference or pointer to the
|
||||
// type of the actual `static` item.
|
||||
Self::in_any_value_of_ty(cx, constant.literal.ty)
|
||||
} else if let ty::ConstKind::Unevaluated(def_id, _) = constant.literal.val {
|
||||
} else if let ty::ConstKind::Unevaluated(def_id, _, promoted) = constant.literal.val
|
||||
{
|
||||
assert!(promoted.is_none());
|
||||
// Don't peek inside trait associated constants.
|
||||
if cx.tcx.trait_of_item(def_id).is_some() {
|
||||
Self::in_any_value_of_ty(cx, constant.literal.ty)
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc::mir::{
|
|||
use rustc::ty::layout::{
|
||||
HasDataLayout, HasTyCtxt, LayoutError, LayoutOf, Size, TargetDataLayout, TyLayout,
|
||||
};
|
||||
use rustc::ty::subst::InternalSubsts;
|
||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
@ -33,7 +33,6 @@ use crate::interpret::{
|
|||
LocalState, LocalValue, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
|
||||
ScalarMaybeUndef, StackPopCleanup,
|
||||
};
|
||||
use crate::rustc::ty::subst::Subst;
|
||||
use crate::transform::{MirPass, MirSource};
|
||||
|
||||
/// The maximum number of bytes that we'll allocate space for a return value.
|
||||
|
@ -265,6 +264,7 @@ struct ConstPropagator<'mir, 'tcx> {
|
|||
// Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
|
||||
// the last known `SourceInfo` here and just keep revisiting it.
|
||||
source_info: Option<SourceInfo>,
|
||||
lint_root: Option<HirId>,
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
|
||||
|
@ -344,6 +344,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
local_decls: body.local_decls.clone(),
|
||||
ret: ret.map(Into::into),
|
||||
source_info: None,
|
||||
lint_root: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,10 +378,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
|
||||
{
|
||||
self.ecx.tcx.span = source_info.span;
|
||||
// FIXME(eddyb) move this to the `Panic(_)` error case, so that
|
||||
// `f(self)` is always called, and that the only difference when the
|
||||
// scope's `local_data` is missing, is that the lint isn't emitted.
|
||||
let lint_root = self.lint_root(source_info)?;
|
||||
let r = match f(self) {
|
||||
Ok(val) => Some(val),
|
||||
Err(error) => {
|
||||
|
@ -414,7 +411,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
diagnostic.report_as_lint(
|
||||
self.ecx.tcx,
|
||||
"this expression will panic at runtime",
|
||||
lint_root,
|
||||
self.lint_root?,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
@ -426,17 +423,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
r
|
||||
}
|
||||
|
||||
fn eval_constant(
|
||||
&mut self,
|
||||
c: &Constant<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
) -> Option<Const<'tcx>> {
|
||||
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
|
||||
self.ecx.tcx.span = c.span;
|
||||
|
||||
// FIXME we need to revisit this for #67176
|
||||
if c.needs_subst() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.ecx.eval_const_to_op(c.literal, None) {
|
||||
Ok(op) => Some(op),
|
||||
Err(error) => {
|
||||
let err = error_to_const_error(&self.ecx, error);
|
||||
match self.lint_root(source_info) {
|
||||
match self.lint_root {
|
||||
Some(lint_root) if c.literal.needs_subst() => {
|
||||
// Out of backwards compatibility we cannot report hard errors in unused
|
||||
// generic functions using associated constants of the generic parameters.
|
||||
|
@ -463,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
|
||||
fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<Const<'tcx>> {
|
||||
match *op {
|
||||
Operand::Constant(ref c) => self.eval_constant(c, source_info),
|
||||
Operand::Constant(ref c) => self.eval_constant(c),
|
||||
Operand::Move(ref place) | Operand::Copy(ref place) => {
|
||||
self.eval_place(place, source_info)
|
||||
}
|
||||
|
@ -552,6 +551,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
// FIXME we need to revisit this for #67176
|
||||
if rvalue.needs_subst() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let overflow_check = self.tcx.sess.overflow_checks();
|
||||
|
||||
// Perform any special handling for specific Rvalue types.
|
||||
|
@ -708,7 +712,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
)) => l.is_bits() && r.is_bits(),
|
||||
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
|
||||
let mplace = op.assert_mem_place(&self.ecx);
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, mplace)
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, mplace, false)
|
||||
.expect("failed to intern alloc");
|
||||
true
|
||||
}
|
||||
|
@ -797,13 +801,14 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
|
||||
trace!("visit_constant: {:?}", constant);
|
||||
self.super_constant(constant, location);
|
||||
self.eval_constant(constant, self.source_info.unwrap());
|
||||
self.eval_constant(constant);
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
|
||||
trace!("visit_statement: {:?}", statement);
|
||||
let source_info = statement.source_info;
|
||||
self.source_info = Some(source_info);
|
||||
self.lint_root = self.lint_root(source_info);
|
||||
if let StatementKind::Assign(box (ref place, ref mut rval)) = statement.kind {
|
||||
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
|
||||
if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
|
||||
|
@ -855,6 +860,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
|||
let source_info = terminator.source_info;
|
||||
self.source_info = Some(source_info);
|
||||
self.super_terminator(terminator, location);
|
||||
self.lint_root = self.lint_root(source_info);
|
||||
match &mut terminator.kind {
|
||||
TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
|
||||
if let Some(value) = self.eval_operand(&cond, source_info) {
|
||||
|
|
|
@ -27,7 +27,7 @@ use rustc_index::vec::{Idx, IndexVec};
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::{iter, mem, usize};
|
||||
use std::{cmp, iter, mem, usize};
|
||||
|
||||
use crate::const_eval::{is_const_fn, is_unstable_const_fn};
|
||||
use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
|
||||
|
@ -761,6 +761,7 @@ struct Promoter<'a, 'tcx> {
|
|||
source: &'a mut BodyAndCache<'tcx>,
|
||||
promoted: BodyAndCache<'tcx>,
|
||||
temps: &'a mut IndexVec<Local, TempState>,
|
||||
extra_statements: &'a mut Vec<(Location, Statement<'tcx>)>,
|
||||
|
||||
/// If true, all nested temps are also kept in the
|
||||
/// source MIR, not moved to the promoted MIR.
|
||||
|
@ -903,7 +904,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
candidate: Candidate,
|
||||
next_promoted_id: usize,
|
||||
) -> Option<BodyAndCache<'tcx>> {
|
||||
let mut operand = {
|
||||
let mut rvalue = {
|
||||
let promoted = &mut self.promoted;
|
||||
let promoted_id = Promoted::new(next_promoted_id);
|
||||
let tcx = self.tcx;
|
||||
|
@ -927,15 +928,70 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
StatementKind::Assign(box (
|
||||
_,
|
||||
Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
|
||||
)) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = place.base.ty(local_decls).ty;
|
||||
let span = statement.source_info.span;
|
||||
|
||||
Operand::Move(Place {
|
||||
base: mem::replace(&mut place.base, promoted_place(ty, span).base),
|
||||
let ref_ty = tcx.mk_ref(
|
||||
tcx.lifetimes.re_static,
|
||||
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
|
||||
);
|
||||
|
||||
promoted.span = span;
|
||||
promoted.local_decls[RETURN_PLACE] =
|
||||
LocalDecl::new_return_place(ref_ty, span);
|
||||
|
||||
*region = tcx.lifetimes.re_static;
|
||||
|
||||
let mut projection = vec![PlaceElem::Deref];
|
||||
projection.extend(place.projection);
|
||||
place.projection = tcx.intern_place_elems(&projection);
|
||||
|
||||
// Create a temp to hold the promoted reference.
|
||||
// This is because `*r` requires `r` to be a local,
|
||||
// otherwise we would use the `promoted` directly.
|
||||
let mut promoted_ref = LocalDecl::new_temp(ref_ty, span);
|
||||
promoted_ref.source_info = statement.source_info;
|
||||
let promoted_ref = local_decls.push(promoted_ref);
|
||||
assert_eq!(self.temps.push(TempState::Unpromotable), promoted_ref);
|
||||
|
||||
let promoted_ref_rvalue =
|
||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: tcx.mk_const(ty::Const {
|
||||
ty: ref_ty,
|
||||
val: ty::ConstKind::Unevaluated(
|
||||
def_id,
|
||||
InternalSubsts::identity_for_item(tcx, def_id),
|
||||
Some(promoted_id),
|
||||
),
|
||||
}),
|
||||
})));
|
||||
let promoted_ref_statement = Statement {
|
||||
source_info: statement.source_info,
|
||||
kind: StatementKind::Assign(Box::new((
|
||||
Place::from(promoted_ref),
|
||||
promoted_ref_rvalue,
|
||||
))),
|
||||
};
|
||||
self.extra_statements.push((loc, promoted_ref_statement));
|
||||
|
||||
Rvalue::Ref(
|
||||
tcx.lifetimes.re_static,
|
||||
borrow_kind,
|
||||
Place {
|
||||
base: mem::replace(
|
||||
&mut place.base,
|
||||
PlaceBase::Local(promoted_ref),
|
||||
),
|
||||
projection: List::empty(),
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
@ -946,7 +1002,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
|
||||
let ty = operand.ty(local_decls, self.tcx);
|
||||
let span = statement.source_info.span;
|
||||
mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
|
||||
Rvalue::Use(mem::replace(
|
||||
operand,
|
||||
Operand::Copy(promoted_place(ty, span)),
|
||||
))
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
@ -958,7 +1017,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
let ty = args[index].ty(local_decls, self.tcx);
|
||||
let span = terminator.source_info.span;
|
||||
let operand = Operand::Copy(promoted_place(ty, span));
|
||||
mem::replace(&mut args[index], operand)
|
||||
Rvalue::Use(mem::replace(&mut args[index], operand))
|
||||
}
|
||||
// We expected a `TerminatorKind::Call` for which we'd like to promote an
|
||||
// argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
|
||||
|
@ -975,13 +1034,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
};
|
||||
|
||||
assert_eq!(self.new_block(), START_BLOCK);
|
||||
self.visit_operand(
|
||||
&mut operand,
|
||||
self.visit_rvalue(
|
||||
&mut rvalue,
|
||||
Location { block: BasicBlock::new(0), statement_index: usize::MAX },
|
||||
);
|
||||
|
||||
let span = self.promoted.span;
|
||||
self.assign(RETURN_PLACE, Rvalue::Use(operand), span);
|
||||
self.assign(RETURN_PLACE, rvalue, span);
|
||||
Some(self.promoted)
|
||||
}
|
||||
}
|
||||
|
@ -1020,6 +1079,7 @@ pub fn promote_candidates<'tcx>(
|
|||
|
||||
let mut promotions = IndexVec::new();
|
||||
|
||||
let mut extra_statements = vec![];
|
||||
for candidate in candidates.into_iter().rev() {
|
||||
match candidate {
|
||||
Candidate::Repeat(Location { block, statement_index })
|
||||
|
@ -1043,8 +1103,7 @@ pub fn promote_candidates<'tcx>(
|
|||
let initial_locals =
|
||||
iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
|
||||
|
||||
let promoter = Promoter {
|
||||
promoted: BodyAndCache::new(Body::new(
|
||||
let mut promoted = Body::new(
|
||||
IndexVec::new(),
|
||||
// FIXME: maybe try to filter this to avoid blowing up
|
||||
// memory usage?
|
||||
|
@ -1056,10 +1115,15 @@ pub fn promote_candidates<'tcx>(
|
|||
body.span,
|
||||
vec![],
|
||||
body.generator_kind,
|
||||
)),
|
||||
);
|
||||
promoted.ignore_interior_mut_in_const_validation = true;
|
||||
|
||||
let promoter = Promoter {
|
||||
promoted: BodyAndCache::new(promoted),
|
||||
tcx,
|
||||
source: body,
|
||||
temps: &mut temps,
|
||||
extra_statements: &mut extra_statements,
|
||||
keep_original: false,
|
||||
};
|
||||
|
||||
|
@ -1069,6 +1133,13 @@ pub fn promote_candidates<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// Insert each of `extra_statements` before its indicated location, which
|
||||
// has to be done in reverse location order, to not invalidate the rest.
|
||||
extra_statements.sort_by_key(|&(loc, _)| cmp::Reverse(loc));
|
||||
for (loc, statement) in extra_statements {
|
||||
body[loc.block].statements.insert(loc.statement_index, statement);
|
||||
}
|
||||
|
||||
// Eliminate assignments to, and drops of promoted temps.
|
||||
let promoted = |index: Local| temps[index] == TempState::PromotedOut;
|
||||
for block in body.basic_blocks_mut() {
|
||||
|
|
|
@ -2697,7 +2697,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let def_id = tcx.hir().local_def_id(ast_const.hir_id);
|
||||
|
||||
let mut const_ = ty::Const {
|
||||
val: ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id)),
|
||||
val: ty::ConstKind::Unevaluated(
|
||||
def_id,
|
||||
InternalSubsts::identity_for_item(tcx, def_id),
|
||||
None,
|
||||
),
|
||||
ty,
|
||||
};
|
||||
|
||||
|
|
|
@ -460,12 +460,16 @@ pub fn name_from_pat(p: &hir::Pat) -> String {
|
|||
|
||||
pub fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
|
||||
match n.val {
|
||||
ty::ConstKind::Unevaluated(def_id, _) => {
|
||||
if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
|
||||
ty::ConstKind::Unevaluated(def_id, _, promoted) => {
|
||||
let mut s = if let Some(hir_id) = cx.tcx.hir().as_local_hir_id(def_id) {
|
||||
print_const_expr(cx, cx.tcx.hir().body_owned_by(hir_id))
|
||||
} else {
|
||||
inline::print_inlined_const(cx, def_id)
|
||||
};
|
||||
if let Some(promoted) = promoted {
|
||||
s.push_str(&format!("{:?}", promoted))
|
||||
}
|
||||
s
|
||||
}
|
||||
_ => {
|
||||
let mut s = n.to_string();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
// This checks the constants from {low,high}_align_const, they share the same
|
||||
// constant, but the alignment differs, so the higher one should be used
|
||||
// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}}, align 4
|
||||
// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @2, i32 0, i32 0, i32 0), {{.*}}, align 8
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
||||
|
@ -44,7 +44,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
|
|||
#[no_mangle]
|
||||
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
|
||||
// CHECK: load %"E<i16, [i16; 3]>"*, %"E<i16, [i16; 3]>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, [i16; 3]>"**), align 8
|
||||
*&E::A(0)
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
|
|||
#[no_mangle]
|
||||
pub fn high_align_const() -> E<i16, i32> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0),
|
||||
// CHECK: load %"E<i16, i32>"*, %"E<i16, i32>"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E<i16, i32>"**), align 8
|
||||
*&E::A(0)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(const_err)]
|
||||
|
||||
// error-pattern: attempt to divide by zero
|
||||
// error-pattern: referenced constant has errors
|
||||
|
||||
fn main() {
|
||||
let x = &(1 / (1 - 1));
|
|
@ -6,7 +6,8 @@ fn main() {
|
|||
// START rustc.main.ConstProp.before.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _2 = &(promoted[0]: i32);
|
||||
// _4 = const main::promoted[0];
|
||||
// _2 = _4;
|
||||
// _1 = (*_2);
|
||||
// ...
|
||||
//}
|
||||
|
@ -14,7 +15,8 @@ fn main() {
|
|||
// START rustc.main.ConstProp.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _2 = &(promoted[0]: i32);
|
||||
// _4 = const main::promoted[0];
|
||||
// _2 = _4;
|
||||
// _1 = const 4i32;
|
||||
// ...
|
||||
// }
|
||||
|
|
|
@ -6,7 +6,8 @@ fn main() {
|
|||
// START rustc.main.ConstProp.before.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _4 = &(promoted[0]: [u32; 3]);
|
||||
// _9 = const main::promoted[0];
|
||||
// _4 = _9;
|
||||
// _3 = _4;
|
||||
// _2 = move _3 as &[u32] (Pointer(Unsize));
|
||||
// ...
|
||||
|
@ -24,7 +25,8 @@ fn main() {
|
|||
// START rustc.main.ConstProp.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _4 = &(promoted[0]: [u32; 3]);
|
||||
// _9 = const main::promoted[0];
|
||||
// _4 = _9;
|
||||
// _3 = _4;
|
||||
// _2 = move _3 as &[u32] (Pointer(Unsize));
|
||||
// ...
|
||||
|
|
|
@ -25,11 +25,11 @@ fn foo(x: &i32, y: &i32) -> bool {
|
|||
// ...
|
||||
// Retag(_3);
|
||||
// Retag(_6);
|
||||
// StorageLive(_9);
|
||||
// _9 = (*_3);
|
||||
// StorageLive(_10);
|
||||
// _10 = (*_6);
|
||||
// _0 = Eq(move _9, move _10);
|
||||
// StorageLive(_11);
|
||||
// _11 = (*_3);
|
||||
// StorageLive(_12);
|
||||
// _12 = (*_6);
|
||||
// _0 = Eq(move _11, move _12);
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
|
|
@ -65,7 +65,8 @@ fn main() {
|
|||
// }
|
||||
// bb6: { // binding1 and guard
|
||||
// StorageLive(_6);
|
||||
// _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32);
|
||||
// _11 = const full_tested_match::promoted[0];
|
||||
// _6 = &(((*_11) as Some).0: i32);
|
||||
// _4 = &shallow _2;
|
||||
// StorageLive(_7);
|
||||
// _7 = const guard() -> [return: bb7, unwind: bb1];
|
||||
|
|
|
@ -4,4 +4,5 @@ fn main() {
|
|||
&{[1, 2, 3][4]};
|
||||
//~^ ERROR index out of bounds
|
||||
//~| ERROR reaching this expression at runtime will panic or abort
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
}
|
||||
|
|
|
@ -14,5 +14,12 @@ LL | &{[1, 2, 3][4]};
|
|||
| |
|
||||
| indexing out of bounds: the len is 3 but the index is 4
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/array-literal-index-oob.rs:4:5
|
||||
|
|
||||
LL | &{[1, 2, 3][4]};
|
||||
| ^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -10,4 +10,5 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
|
|||
fn main() {
|
||||
println!("{}", FOO);
|
||||
//~^ ERROR
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
}
|
||||
|
|
|
@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed
|
|||
LL | println!("{}", FOO);
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/conditional_array_execution.rs:11:20
|
||||
|
|
||||
LL | println!("{}", FOO);
|
||||
| ^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -17,6 +17,8 @@ const Z: usize = bar(double, 2); // FIXME: should fail to typeck someday
|
|||
fn main() {
|
||||
assert_eq!(Y, 4);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
assert_eq!(Z, 4);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
}
|
||||
|
|
|
@ -14,8 +14,16 @@ LL | assert_eq!(Y, 4);
|
|||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/const_fn_ptr_fail2.rs:18:5
|
||||
|
|
||||
LL | assert_eq!(Y, 4);
|
||||
| ^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/const_fn_ptr_fail2.rs:20:5
|
||||
--> $DIR/const_fn_ptr_fail2.rs:21:5
|
||||
|
|
||||
LL | assert_eq!(Z, 4);
|
||||
| ^^^^^^^^^^^-^^^^^
|
||||
|
@ -24,6 +32,14 @@ LL | assert_eq!(Z, 4);
|
|||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/const_fn_ptr_fail2.rs:21:5
|
||||
|
|
||||
LL | assert_eq!(Z, 4);
|
||||
| ^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
|
||||
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -14,4 +14,6 @@ fn main() {
|
|||
println!("{} {}", X, Y);
|
||||
//~^ ERROR evaluation of constant expression failed
|
||||
//~| ERROR evaluation of constant expression failed
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
}
|
||||
|
|
|
@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed
|
|||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-43197.rs:14:23
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/issue-43197.rs:14:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-43197.rs:14:26
|
||||
|
|
||||
LL | println!("{} {}", X, Y);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -25,5 +25,6 @@ impl Foo for u16 {
|
|||
|
||||
fn main() {
|
||||
println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
//~^ ERROR E0080
|
||||
//~^ ERROR erroneous constant used [E0080]
|
||||
//~| ERROR evaluation of constant expression failed [E0080]
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ error[E0080]: evaluation of constant expression failed
|
|||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/issue-44578.rs:27:20
|
||||
|
|
||||
LL | println!("{}", <Bar<u16, u8> as Foo>::AMT);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -12,11 +12,13 @@ impl Unsigned for U8 {
|
|||
struct Sum<A,B>(A,B);
|
||||
|
||||
impl<A: Unsigned, B: Unsigned> Unsigned for Sum<A,B> {
|
||||
const MAX: u8 = A::MAX + B::MAX; //~ ERROR any use of this value will cause an error
|
||||
const MAX: u8 = A::MAX + B::MAX;
|
||||
//~^ ERROR any use of this value will cause an error [const_err]
|
||||
}
|
||||
|
||||
fn foo<T>(_: T) -> &'static u8 {
|
||||
&Sum::<U8,U8>::MAX //~ ERROR E0080
|
||||
&Sum::<U8,U8>::MAX
|
||||
//~^ ERROR E0080
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -9,7 +9,7 @@ LL | const MAX: u8 = A::MAX + B::MAX;
|
|||
= note: `#[deny(const_err)]` on by default
|
||||
|
||||
error[E0080]: evaluation of constant expression failed
|
||||
--> $DIR/issue-50814.rs:19:5
|
||||
--> $DIR/issue-50814.rs:20:5
|
||||
|
|
||||
LL | &Sum::<U8,U8>::MAX
|
||||
| ^-----------------
|
||||
|
|
|
@ -10,11 +10,13 @@ fn main() {
|
|||
println!("{}", 1/(1-1));
|
||||
//~^ ERROR attempt to divide by zero [const_err]
|
||||
//~| ERROR const_err
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
let _x = 1/(1-1);
|
||||
//~^ ERROR const_err
|
||||
println!("{}", 1/(false as u32));
|
||||
//~^ ERROR attempt to divide by zero [const_err]
|
||||
//~| ERROR const_err
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
let _x = 1/(false as u32);
|
||||
//~^ ERROR const_err
|
||||
}
|
||||
|
|
|
@ -22,29 +22,42 @@ error: reaching this expression at runtime will panic or abort
|
|||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ dividing by zero
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/promoted_errors.rs:10:20
|
||||
|
|
||||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ referenced constant has errors
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:13:14
|
||||
--> $DIR/promoted_errors.rs:14:14
|
||||
|
|
||||
LL | let _x = 1/(1-1);
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:15:20
|
||||
--> $DIR/promoted_errors.rs:16:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: reaching this expression at runtime will panic or abort
|
||||
--> $DIR/promoted_errors.rs:15:20
|
||||
--> $DIR/promoted_errors.rs:16:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ dividing by zero
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/promoted_errors.rs:16:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:18:14
|
||||
--> $DIR/promoted_errors.rs:20:14
|
||||
|
|
||||
LL | let _x = 1/(false as u32);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -11,11 +11,13 @@ fn main() {
|
|||
println!("{}", 1/(1-1));
|
||||
//~^ ERROR attempt to divide by zero [const_err]
|
||||
//~| ERROR const_err
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
let _x = 1/(1-1);
|
||||
//~^ ERROR const_err
|
||||
println!("{}", 1/(false as u32));
|
||||
//~^ ERROR attempt to divide by zero [const_err]
|
||||
//~| ERROR const_err
|
||||
//~| ERROR erroneous constant used [E0080]
|
||||
let _x = 1/(false as u32);
|
||||
//~^ ERROR const_err
|
||||
}
|
||||
|
|
|
@ -28,29 +28,42 @@ error: reaching this expression at runtime will panic or abort
|
|||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ dividing by zero
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/promoted_errors2.rs:11:20
|
||||
|
|
||||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ referenced constant has errors
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors2.rs:14:14
|
||||
--> $DIR/promoted_errors2.rs:15:14
|
||||
|
|
||||
LL | let _x = 1/(1-1);
|
||||
| ^^^^^^^
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors2.rs:16:20
|
||||
--> $DIR/promoted_errors2.rs:17:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: reaching this expression at runtime will panic or abort
|
||||
--> $DIR/promoted_errors2.rs:16:20
|
||||
--> $DIR/promoted_errors2.rs:17:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ dividing by zero
|
||||
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/promoted_errors2.rs:17:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ referenced constant has errors
|
||||
|
||||
error: attempt to divide by zero
|
||||
--> $DIR/promoted_errors2.rs:19:14
|
||||
--> $DIR/promoted_errors2.rs:21:14
|
||||
|
|
||||
LL | let _x = 1/(false as u32);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
|
|||
LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
|
||||
LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL!
|
||||
LL | | let out_of_bounds_ptr = &ptr[255];
|
||||
| | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 6 which has size 1
|
||||
| | ^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of allocation 8 which has size 1
|
||||
LL | | mem::transmute(out_of_bounds_ptr)
|
||||
LL | | } };
|
||||
| |____-
|
||||
|
|
|
@ -11,5 +11,7 @@ const C: () = foo(); //~ WARN: skipping const checks
|
|||
//~^ WARN any use of this value will cause an error
|
||||
|
||||
fn main() {
|
||||
println!("{:?}", C); //~ ERROR: evaluation of constant expression failed
|
||||
println!("{:?}", C);
|
||||
//~^ ERROR: evaluation of constant expression failed
|
||||
//~| ERROR: erroneous constant used [E0080]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed
|
|||
LL | println!("{:?}", C);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0080]: erroneous constant used
|
||||
--> $DIR/non_const_fn.rs:14:22
|
||||
|
|
||||
LL | println!("{:?}", C);
|
||||
| ^ referenced constant has errors
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
|
|
@ -7,13 +7,15 @@ static FOO: Foo = Foo;
|
|||
|
||||
fn main() {
|
||||
let x: &'static () = &();
|
||||
assert_eq!(x as *const () as usize, 1);
|
||||
assert_ne!(x as *const () as usize, 1);
|
||||
let x: &'static Foo = &Foo;
|
||||
assert_eq!(x as *const Foo as usize, 4);
|
||||
assert_ne!(x as *const Foo as usize, 4);
|
||||
|
||||
// statics must have a unique address
|
||||
assert_ne!(&FOO as *const Foo as usize, 4);
|
||||
|
||||
assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
|
||||
assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
|
||||
// FIXME this two tests should be assert_eq!
|
||||
// this stopped working since we are promoting to constants instead of statics
|
||||
assert_ne!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
|
||||
assert_ne!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(unused_mut)]
|
||||
// ignore-wasm32
|
||||
// ignore-emscripten
|
||||
// ignore-sgx no processes
|
||||
|
||||
// compile-flags: -C debug_assertions=yes
|
||||
|
||||
#![stable(feature = "rustc", since = "1.0.0")]
|
||||
#![feature(const_fn, rustc_private, staged_api, rustc_attrs)]
|
||||
#![allow(const_err)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use std::env;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
// this will panic in debug mode and overflow in release mode
|
||||
//
|
||||
// NB we give bar an unused argument because otherwise memoization
|
||||
// of the const fn kicks in, causing a different code path in the
|
||||
// compiler to be executed (see PR #66294).
|
||||
#[stable(feature = "rustc", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
|
||||
#[rustc_promotable]
|
||||
const fn bar(_: bool) -> usize { 0 - 1 }
|
||||
|
||||
fn foo() {
|
||||
let _: &'static _ = &bar(true);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn check_status(status: std::process::ExitStatus)
|
||||
{
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
assert!(status.signal() == Some(libc::SIGILL)
|
||||
|| status.signal() == Some(libc::SIGTRAP)
|
||||
|| status.signal() == Some(libc::SIGABRT));
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn check_status(status: std::process::ExitStatus)
|
||||
{
|
||||
assert!(!status.success());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() > 1 && args[1] == "test" {
|
||||
foo();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut p = Command::new(&args[0])
|
||||
.stdout(Stdio::piped())
|
||||
.stdin(Stdio::piped())
|
||||
.arg("test").output().unwrap();
|
||||
check_status(p.status);
|
||||
}
|
|
@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
|
|||
LL | #[rustc_def_path]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17h92c563325b7ff21aE)
|
||||
error: symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$_$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method17hf07584432cd4d8beE)
|
||||
--> $DIR/impl1.rs:62:13
|
||||
|
|
||||
LL | #[rustc_symbol_name]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::h92c563325b7ff21a)
|
||||
error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; _] as impl1::main::{{closure}}::Bar>::method::hf07584432cd4d8be)
|
||||
--> $DIR/impl1.rs:62:13
|
||||
|
|
||||
LL | #[rustc_symbol_name]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue