提交 16887192 编写于 作者: S Santiago Pastorino 提交者: Oliver Scherer

Promote `Ref`s to constants instead of static

上级 a59abfa4
......@@ -36,11 +36,16 @@ pub fn const_eval_resolve(
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)
}
......
......@@ -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 @@ pub fn new(
spread_arg: None,
var_debug_info,
span,
ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
}
}
......
......@@ -515,6 +515,7 @@ fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
obligation.param_env,
def_id,
substs,
None,
Some(obligation.cause.span),
) {
Ok(_) => ProcessResult::Changed(vec![]),
......
......@@ -802,8 +802,13 @@ fn evaluate_predicate_recursively<'o>(
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 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'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 @@ fn add_region(&mut self, r: ty::Region<'_>) {
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,23 +841,31 @@ fn pretty_print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const
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),
......
......@@ -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 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
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::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 @@ pub fn try_eval_bits(
#[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 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'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 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'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 @@ pub fn eval_mir_constant_to_operand(
// 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 @@ pub fn eval_mir_constant(
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,17 +310,54 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
);
}
} 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 {
......
......@@ -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,9 +176,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
......
......@@ -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,
......
......@@ -749,6 +749,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
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 @@ fn visit_aggregate(
// 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;
......@@ -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 @@ pub(super) fn eval_operands(
// 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 @@ fn in_operand(
// 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::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 @@
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 @@ fn new(
local_decls: body.local_decls.clone(),
ret: ret.map(Into::into),
source_info: None,
lint_root: None,
}
}
......@@ -377,10 +378,6 @@ fn use_ecx<F, T>(&mut self, source_info: SourceInfo, f: F) -> Option<T>
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 @@ fn use_ecx<F, T>(&mut self, source_info: SourceInfo, f: F) -> Option<T>
diagnostic.report_as_lint(
self.ecx.tcx,
"this expression will panic at runtime",
lint_root,
self.lint_root?,
None,
);
}
......@@ -426,17 +423,19 @@ fn use_ecx<F, T>(&mut self, source_info: SourceInfo, f: F) -> Option<T>
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 @@ fn eval_place(&mut self, place: &Place<'tcx>, source_info: SourceInfo) -> Option
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 @@ fn const_prop(
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 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
)) => 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 @@ fn tcx(&self) -> TyCtxt<'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 @@ fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Loca
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_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 @@ fn promote_candidate(
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 @@ fn promote_candidate(
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!(),
}
......@@ -946,7 +1002,10 @@ fn promote_candidate(
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 @@ fn promote_candidate(
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 @@ fn promote_candidate(
};
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,23 +1103,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,
};
......@@ -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 @@ pub fn ast_const_to_const(
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 inline_enum_const() -> E<i8, i16> {
#[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)
}
#![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 @@
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 fn bar(x: fn(usize) -> usize, y: usize) -> usize {
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 @@ fn foo() {}
//~^ 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 @@
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());
}
// 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]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册