Skip to content

Instantly share code, notes, and snippets.

@spastorino
Created December 28, 2019 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spastorino/31917c9f06a578b2ed40a9b5bb781e29 to your computer and use it in GitHub Desktop.
Save spastorino/31917c9f06a578b2ed40a9b5bb781e29 to your computer and use it in GitHub Desktop.
commit a2263d3bcd577949208df9cffcc985e6d0196e84
Author: Santiago Pastorino <spastorino@gmail.com>
Date: Fri Nov 22 17:26:09 2019 -0300
Promote `Ref`s to constants instead of static
diff --git a/src/librustc/mir/interpret/queries.rs b/src/librustc/mir/interpret/queries.rs
index e6caa146a62..e219e0b7eef 100644
--- a/src/librustc/mir/interpret/queries.rs
+++ b/src/librustc/mir/interpret/queries.rs
@@ -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 {
- self.const_eval_instance(param_env, instance, span)
+ if let Some(promoted) = promoted {
+ self.const_eval_promoted(instance, promoted)
+ } else {
+ self.const_eval_instance(param_env, instance, span)
+ }
} else {
Err(ErrorHandled::TooGeneric)
}
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index dc74ff1e98d..3fb14d43891 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -165,6 +165,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> {
@@ -201,6 +211,7 @@ impl<'tcx> Body<'tcx> {
spread_arg: None,
var_debug_info,
span,
+ ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
}
}
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 614375287ba..76ca3eaca55 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -514,6 +514,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![]),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index f11fcc4ebae..a4f61fd9702 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -800,8 +800,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),
}
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index b9aa12b4665..4a4280ba7dc 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -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);
}
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 9bd7701da1f..3175b58221f 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -841,23 +841,31 @@ 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))
- }
- _ => {
- if did.is_local() {
- let span = self.tcx().def_span(did);
- if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
- p!(write("{}", snip))
- } else {
- p!(write("_: "), print(ct.ty))
+ (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)
+ {
+ p!(write("{}", snip))
+ } else {
+ p!(write("_: "), print(ct.ty))
+ }
+ } else {
+ p!(write("_: "), print(ct.ty))
+ }
}
- } else {
- 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),
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 120f05ba7d9..b780c8dc1f6 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -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))),
};
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 61ee7288a9b..76fb7ce1061 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -1044,8 +1044,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
@@ -1057,7 +1057,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
}
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index c17fff29810..278aec5c441 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -11,6 +11,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};
@@ -2376,7 +2377,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.
@@ -2388,11 +2389,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.
@@ -2402,12 +2403,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,
@@ -2471,7 +2472,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>),
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 9e0dd8e067a..da08fbcf144 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -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);
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 900c425fac2..3bfcb6bdacf 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -358,7 +358,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);
diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs
index 2a4329cdb06..10d4177fe74 100644
--- a/src/librustc_codegen_ssa/mir/constant.rs
+++ b/src/librustc_codegen_ssa/mir/constant.rs
@@ -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()
diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs
index db7db03bde0..254af9094b0 100644
--- a/src/librustc_mir/borrow_check/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/type_check/mod.rs
@@ -309,17 +309,54 @@ 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 Err(terr) = self.cx.fully_perform_op(
- location.to_locations(),
- ConstraintCategory::Boring,
- self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
- constant.literal.ty,
- def_id,
- UserSubsts { substs, user_self_ty: None },
- )),
- ) {
- span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
+ 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,
+ self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
+ constant.literal.ty,
+ def_id,
+ UserSubsts { substs, user_self_ty: None },
+ )),
+ ) {
+ span_mirbug!(
+ self,
+ constant,
+ "bad constant type {:?} ({:?})",
+ constant,
+ terr
+ );
+ }
}
}
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 63e63f304d2..56bb5ef3b40 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -51,7 +51,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())),
diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs
index 745b6aabfa6..16fa48ba79c 100644
--- a/src/librustc_mir/const_eval/eval_queries.rs
+++ b/src/librustc_mir/const_eval/eval_queries.rs
@@ -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)
@@ -168,9 +173,14 @@ 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)?;
- 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))?;
+
+ // 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
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 124b788fe8d..34be71fdf3c 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -411,15 +411,18 @@ 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)) {
- 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");
- 0
- }
- };
+ 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");
+ 0
+ }
+ };
ExprKind::Repeat { value: v.to_ref(), count }
}
@@ -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,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index 6dd3c0f80da..c03ca245a6e 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -742,7 +742,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let kind = match res {
Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
let substs = self.tables.node_substs(id);
- match self.tcx.const_eval_resolve(self.param_env, def_id, substs, Some(span)) {
+ match self.tcx.const_eval_resolve(self.param_env, def_id, substs, None, Some(span))
+ {
Ok(value) => {
let pattern = self.const_to_pat(value, id, span);
if !is_associated_const {
diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs
index dffc8e8256c..335c96ce538 100644
--- a/src/librustc_mir/interpret/intern.rs
+++ b/src/librustc_mir/interpret/intern.rs
@@ -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);
- 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.",
- );
+ 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.",
+ );
+ }
let walked = self.walk_aggregate(mplace, fields);
self.mutability = old;
return walked;
@@ -265,6 +272,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 {
@@ -301,6 +309,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 {
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index def979b63b5..adca5ea5e3a 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -576,7 +576,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
@@ -586,7 +586,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// happening.
// FIXME(oli-obk): eliminate all the `const_eval_raw` usages when we get rid of
// `StaticKind` once and for all.
- return self.const_eval(GlobalId { instance, promoted: None });
+ return self.const_eval(GlobalId { instance, promoted });
}
ty::ConstKind::Infer(..)
| ty::ConstKind::Bound(..)
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 0a783337ad1..c06f3b42d08 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1253,8 +1253,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) => {
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 746d83b05c6..741fadc117e 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -103,7 +103,9 @@ pub trait Qualif {
Operand::Constant(ref constant) => {
if let Some(static_) = constant.check_static_ptr(cx.tcx) {
Self::in_static(cx, static_)
- } 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)
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index a6b30ab5e68..4b42d51b92b 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -6,6 +6,7 @@ use std::cell::Cell;
use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
+use rustc::hir::HirId;
use rustc::mir::interpret::{InterpResult, PanicInfo, Scalar};
use rustc::mir::visit::{
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
@@ -33,6 +34,7 @@ use crate::interpret::{
ScalarMaybeUndef, StackPopCleanup,
};
use crate::rustc::ty::subst::Subst;
+use crate::rustc::ty::TypeFoldable;
use crate::transform::{MirPass, MirSource};
/// The maximum number of bytes that we'll allocate space for a return value.
@@ -260,6 +262,7 @@ struct ConstPropagator<'mir, 'tcx> {
source_scopes: IndexVec<SourceScope, SourceScopeData>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
ret: Option<OpTy<'tcx, ()>>,
+ lint_root: Option<HirId>,
}
impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
@@ -331,6 +334,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
local_decls: body.local_decls.clone(),
ret: ret.map(Into::into),
+ lint_root: None,
}
}
@@ -357,13 +361,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 = match &self.source_scopes[source_info.scope].local_data {
- ClearCrossCrate::Set(data) => data.lint_root,
- ClearCrossCrate::Clear => return None,
- };
let r = match f(self) {
Ok(val) => Some(val),
Err(error) => {
@@ -397,7 +394,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,
);
}
@@ -411,11 +408,28 @@ impl<'mir, 'tcx> ConstPropagator<'mir, '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);
- err.report_as_error(self.ecx.tcx, "erroneous constant used");
+
+ if let ty::ConstKind::Unevaluated(_, _, Some(_)) = c.literal.val {
+ err.report_as_lint(
+ self.ecx.tcx,
+ "erroneous constant used",
+ self.lint_root?,
+ Some(c.span),
+ );
+ } else {
+ err.report_as_error(self.ecx.tcx, "erroneous constant used");
+ }
+
None
}
}
@@ -449,6 +463,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.
@@ -495,14 +514,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let right_size = r.layout.size;
let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
if r_bits.map_or(false, |b| b >= left_bits as u128) {
- let lint_root = match &self.source_scopes[source_info.scope].local_data {
- ClearCrossCrate::Set(data) => data.lint_root,
- ClearCrossCrate::Clear => return None,
- };
let dir = if *op == BinOp::Shr { "right" } else { "left" };
self.tcx.lint_hir(
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
- lint_root,
+ self.lint_root?,
span,
&format!("attempt to shift {} with overflow", dir),
);
@@ -659,7 +674,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ScalarMaybeUndef::Scalar(r),
)) => l.is_bits() && r.is_bits(),
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
- intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place())
+ intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place(), false)
.expect("failed to intern alloc");
true
}
@@ -753,6 +768,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
trace!("visit_statement: {:?}", statement);
+ self.lint_root = match &self.source_scopes[statement.source_info.scope].local_data {
+ ClearCrossCrate::Set(data) => Some(data.lint_root),
+ ClearCrossCrate::Clear => None,
+ };
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)) {
@@ -804,6 +823,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
self.super_terminator(terminator, location);
let source_info = terminator.source_info;
+ self.lint_root = match &self.source_scopes[source_info.scope].local_data {
+ ClearCrossCrate::Set(data) => Some(data.lint_root),
+ ClearCrossCrate::Clear => None,
+ };
match &mut terminator.kind {
TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
if let Some(value) = self.eval_operand(&cond, source_info) {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index b52231e55f9..d121ff108d9 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -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::transform::check_consts::{is_lang_panic_fn, qualifs, ConstKind, Item};
use crate::transform::{MirPass, MirSource};
@@ -760,6 +760,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.
@@ -902,7 +903,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;
@@ -926,15 +927,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),
- projection: List::empty(),
- })
+ 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!(),
}
@@ -945,7 +1001,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!(),
}
@@ -957,7 +1016,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
@@ -974,13 +1033,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)
}
}
@@ -1019,6 +1078,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 })
@@ -1042,23 +1102,27 @@ pub fn promote_candidates<'tcx>(
let initial_locals =
iter::once(LocalDecl::new_return_place(tcx.types.never, body.span)).collect();
+ let mut promoted = Body::new(
+ IndexVec::new(),
+ // FIXME: maybe try to filter this to avoid blowing up
+ // memory usage?
+ body.source_scopes.clone(),
+ initial_locals,
+ IndexVec::new(),
+ 0,
+ vec![],
+ body.span,
+ vec![],
+ body.generator_kind,
+ );
+ promoted.ignore_interior_mut_in_const_validation = true;
+
let promoter = Promoter {
- promoted: BodyAndCache::new(Body::new(
- IndexVec::new(),
- // FIXME: maybe try to filter this to avoid blowing up
- // memory usage?
- body.source_scopes.clone(),
- initial_locals,
- IndexVec::new(),
- 0,
- vec![],
- body.span,
- vec![],
- body.generator_kind,
- )),
+ promoted: BodyAndCache::new(promoted),
tcx,
source: body,
temps: &mut temps,
+ extra_statements: &mut extra_statements,
keep_original: false,
};
@@ -1068,6 +1132,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() {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 8e0f5d17b9f..2912a02139e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -2678,7 +2678,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,
};
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index e52afe501c3..1e26076bdf7 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -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();
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index 7d65ad1435e..a5478a03791 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -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)
}
diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs
index d45ffdc8775..6b5101af5fc 100644
--- a/src/test/mir-opt/const_prop/ref_deref.rs
+++ b/src/test/mir-opt/const_prop/ref_deref.rs
@@ -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;
// ...
// }
diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs
index d6ff76b34b9..43813e43d36 100644
--- a/src/test/mir-opt/const_prop/slice_len.rs
+++ b/src/test/mir-opt/const_prop/slice_len.rs
@@ -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));
// ...
diff --git a/src/test/mir-opt/inline/inline-retag.rs b/src/test/mir-opt/inline/inline-retag.rs
index 6cdbcfdb0ad..7b78fc339f2 100644
--- a/src/test/mir-opt/inline/inline-retag.rs
+++ b/src/test/mir-opt/inline/inline-retag.rs
@@ -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;
// }
diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs
index 648856b5523..2c20c35e4a4 100644
--- a/src/test/mir-opt/match_false_edges.rs
+++ b/src/test/mir-opt/match_false_edges.rs
@@ -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];
diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs
index 1de6bafd293..af7df5f1ff6 100644
--- a/src/test/ui/consts/array-literal-index-oob.rs
+++ b/src/test/ui/consts/array-literal-index-oob.rs
@@ -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 [const_err]
}
diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr
index f3ef16659dd..8f5de704f6e 100644
--- a/src/test/ui/consts/array-literal-index-oob.stderr
+++ b/src/test/ui/consts/array-literal-index-oob.stderr
@@ -14,5 +14,11 @@ 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: 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
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.rs b/src/test/ui/consts/const-eval/conditional_array_execution.rs
index 96f67c92a5e..2058d2e2184 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.rs
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.rs
@@ -10,4 +10,5 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
fn main() {
println!("{}", FOO);
//~^ ERROR
+ //~| WARN erroneous constant used [const_err]
}
diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
index ec18f8f011d..b5f5f84cf38 100644
--- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr
+++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr
@@ -18,6 +18,12 @@ error[E0080]: evaluation of constant expression failed
LL | println!("{}", FOO);
| ^^^ referenced constant has errors
+warning: erroneous constant used
+ --> $DIR/conditional_array_execution.rs:11:20
+ |
+LL | println!("{}", FOO);
+ | ^^^ referenced constant has errors
+
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-43197.rs b/src/test/ui/consts/const-eval/issue-43197.rs
index 849c81ad449..04de6b11718 100644
--- a/src/test/ui/consts/const-eval/issue-43197.rs
+++ b/src/test/ui/consts/const-eval/issue-43197.rs
@@ -14,4 +14,6 @@ fn main() {
println!("{} {}", X, Y);
//~^ ERROR evaluation of constant expression failed
//~| ERROR evaluation of constant expression failed
+ //~| WARN erroneous constant used [const_err]
+ //~| WARN erroneous constant used [const_err]
}
diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr
index a1b3a05ed41..ccbb51edf17 100644
--- a/src/test/ui/consts/const-eval/issue-43197.stderr
+++ b/src/test/ui/consts/const-eval/issue-43197.stderr
@@ -26,12 +26,24 @@ error[E0080]: evaluation of constant expression failed
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
+warning: 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
+warning: erroneous constant used
+ --> $DIR/issue-43197.rs:14:26
+ |
+LL | println!("{} {}", X, Y);
+ | ^ referenced constant has errors
+
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-50814.rs b/src/test/ui/consts/const-eval/issue-50814.rs
index e589126a942..5c3635e4650 100644
--- a/src/test/ui/consts/const-eval/issue-50814.rs
+++ b/src/test/ui/consts/const-eval/issue-50814.rs
@@ -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() {
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index f8b017e4b53..2e5167a99a2 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -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
| ^-----------------
diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs
index 2eed8ca7d32..c055541d6e4 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors.rs
@@ -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 [const_err]
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 [const_err]
let _x = 1/(false as u32);
//~^ ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr
index 8f17ef05f23..63e4a130ad4 100644
--- a/src/test/ui/consts/const-eval/promoted_errors.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors.stderr
@@ -22,29 +22,41 @@ error: reaching this expression at runtime will panic or abort
LL | println!("{}", 1/(1-1));
| ^^^^^^^ dividing by zero
+error: 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: 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
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.rs b/src/test/ui/consts/const-eval/promoted_errors2.rs
index ae680b4f107..7272e7898d0 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.rs
+++ b/src/test/ui/consts/const-eval/promoted_errors2.rs
@@ -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 [const_err]
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 [const_err]
let _x = 1/(false as u32);
//~^ ERROR const_err
}
diff --git a/src/test/ui/consts/const-eval/promoted_errors2.stderr b/src/test/ui/consts/const-eval/promoted_errors2.stderr
index 60a3cba6e1f..607a6ff8cf1 100644
--- a/src/test/ui/consts/const-eval/promoted_errors2.stderr
+++ b/src/test/ui/consts/const-eval/promoted_errors2.stderr
@@ -28,29 +28,41 @@ error: reaching this expression at runtime will panic or abort
LL | println!("{}", 1/(1-1));
| ^^^^^^^ dividing by zero
+error: 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: 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
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr
index 80d80a98675..c2446d14040 100644
--- a/src/test/ui/consts/const-eval/ub-nonnull.stderr
+++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr
@@ -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 | | } };
| |____-
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.rs b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
index 32a713ebaa4..cfb57d21cee 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.rs
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.rs
@@ -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
+ //~| WARN: erroneous constant used [const_err]
}
diff --git a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
index 75f532a81bd..6a7df858feb 100644
--- a/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
+++ b/src/test/ui/consts/miri_unleashed/non_const_fn.stderr
@@ -24,6 +24,12 @@ error[E0080]: evaluation of constant expression failed
LL | println!("{:?}", C);
| ^ referenced constant has errors
+warning: erroneous constant used
+ --> $DIR/non_const_fn.rs:14:22
+ |
+LL | println!("{:?}", C);
+ | ^ referenced constant has errors
+
error: aborting due to previous error
For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/zst_no_llvm_alloc.rs b/src/test/ui/consts/zst_no_llvm_alloc.rs
index 5d779355400..2a41f708c2b 100644
--- a/src/test/ui/consts/zst_no_llvm_alloc.rs
+++ b/src/test/ui/consts/zst_no_llvm_alloc.rs
@@ -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());
}
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
deleted file mode 100644
index 5d7664cefb3..00000000000
--- a/src/test/ui/invalid_const_promotion.rs
+++ /dev/null
@@ -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);
-}
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index 53ab2f9878f..affb5537b18 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -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]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment