Skip to content

Commit 1688719

Browse files
spastorinooli-obk
authored andcommitted
Promote Refs to constants instead of static
1 parent a59abfa commit 1688719

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+447
-223
lines changed

src/librustc/mir/interpret/queries.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> {
3636
param_env: ty::ParamEnv<'tcx>,
3737
def_id: DefId,
3838
substs: SubstsRef<'tcx>,
39+
promoted: Option<mir::Promoted>,
3940
span: Option<Span>,
4041
) -> ConstEvalResult<'tcx> {
4142
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
4243
if let Some(instance) = instance {
43-
self.const_eval_instance(param_env, instance, span)
44+
if let Some(promoted) = promoted {
45+
self.const_eval_promoted(instance, promoted)
46+
} else {
47+
self.const_eval_instance(param_env, instance, span)
48+
}
4449
} else {
4550
Err(ErrorHandled::TooGeneric)
4651
}

src/librustc/mir/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ pub struct Body<'tcx> {
166166

167167
/// A span representing this MIR, for error reporting.
168168
pub span: Span,
169+
170+
/// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
171+
/// we'd statically know that no thing with interior mutability will ever be available to the
172+
/// user without some serious unsafe code. Now this means that our promoted is actually
173+
/// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
174+
/// index may be a runtime value. Such a promoted value is illegal because it has reachable
175+
/// interior mutability. This flag just makes this situation very obvious where the previous
176+
/// implementation without the flag hid this situation silently.
177+
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
178+
pub ignore_interior_mut_in_const_validation: bool,
169179
}
170180

171181
impl<'tcx> Body<'tcx> {
@@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> {
202212
spread_arg: None,
203213
var_debug_info,
204214
span,
215+
ignore_interior_mut_in_const_validation: false,
205216
control_flow_destroyed,
206217
}
207218
}

src/librustc/traits/fulfill.rs

+1
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
515515
obligation.param_env,
516516
def_id,
517517
substs,
518+
None,
518519
Some(obligation.cause.span),
519520
) {
520521
Ok(_) => ProcessResult::Changed(vec![]),

src/librustc/traits/select.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -802,8 +802,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
802802

803803
ty::Predicate::ConstEvaluatable(def_id, substs) => {
804804
if !(obligation.param_env, substs).has_local_value() {
805-
match self.tcx().const_eval_resolve(obligation.param_env, def_id, substs, None)
806-
{
805+
match self.tcx().const_eval_resolve(
806+
obligation.param_env,
807+
def_id,
808+
substs,
809+
None,
810+
None,
811+
) {
807812
Ok(_) => Ok(EvaluatedToOk),
808813
Err(_) => Ok(EvaluatedToErr),
809814
}

src/librustc/traits/wf.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
359359
/// Pushes the obligations required for an array length to be WF
360360
/// into `self.out`.
361361
fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
362-
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
362+
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
363+
assert!(promoted.is_none());
364+
363365
let obligations = self.nominal_obligations(def_id, substs);
364366
self.out.extend(obligations);
365367

src/librustc/ty/flags.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl FlagComputation {
219219
fn add_const(&mut self, c: &ty::Const<'_>) {
220220
self.add_ty(c.ty);
221221
match c.val {
222-
ty::ConstKind::Unevaluated(_, substs) => {
222+
ty::ConstKind::Unevaluated(_, substs, _) => {
223223
self.add_substs(substs);
224224
self.add_flags(TypeFlags::HAS_PROJECTION);
225225
}

src/librustc/ty/print/pretty.rs

+22-14
Original file line numberDiff line numberDiff line change
@@ -841,23 +841,31 @@ pub trait PrettyPrinter<'tcx>:
841841

842842
match (ct.val, &ct.ty.kind) {
843843
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
844-
(ty::ConstKind::Unevaluated(did, substs), _) => match self.tcx().def_kind(did) {
845-
Some(DefKind::Static) | Some(DefKind::Const) | Some(DefKind::AssocConst) => {
846-
p!(print_value_path(did, substs))
847-
}
848-
_ => {
849-
if did.is_local() {
850-
let span = self.tcx().def_span(did);
851-
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
852-
p!(write("{}", snip))
853-
} else {
854-
p!(write("_: "), print(ct.ty))
844+
(ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
845+
if let Some(promoted) = promoted {
846+
p!(print_value_path(did, substs));
847+
p!(write("::{:?}", promoted));
848+
} else {
849+
match self.tcx().def_kind(did) {
850+
Some(DefKind::Static)
851+
| Some(DefKind::Const)
852+
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
853+
_ => {
854+
if did.is_local() {
855+
let span = self.tcx().def_span(did);
856+
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
857+
{
858+
p!(write("{}", snip))
859+
} else {
860+
p!(write("_: "), print(ct.ty))
861+
}
862+
} else {
863+
p!(write("_: "), print(ct.ty))
864+
}
855865
}
856-
} else {
857-
p!(write("_: "), print(ct.ty))
858866
}
859867
}
860-
},
868+
}
861869
(ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),
862870
(ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
863871
(ty::ConstKind::Value(value), _) => return self.pretty_print_const_value(value, ct.ty),

src/librustc/ty/relate.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -568,12 +568,12 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
568568

569569
// FIXME(const_generics): this is wrong, as it is a projection
570570
(
571-
ty::ConstKind::Unevaluated(a_def_id, a_substs),
572-
ty::ConstKind::Unevaluated(b_def_id, b_substs),
573-
) if a_def_id == b_def_id => {
571+
ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
572+
ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
573+
) if a_def_id == b_def_id && a_promoted == b_promoted => {
574574
let substs =
575575
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
576-
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
576+
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
577577
}
578578
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
579579
};

src/librustc/ty/structural_impls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1037,8 +1037,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
10371037
match *self {
10381038
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
10391039
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
1040-
ty::ConstKind::Unevaluated(did, substs) => {
1041-
ty::ConstKind::Unevaluated(did, substs.fold_with(folder))
1040+
ty::ConstKind::Unevaluated(did, substs, promoted) => {
1041+
ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
10421042
}
10431043
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(..) => {
10441044
*self
@@ -1050,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
10501050
match *self {
10511051
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
10521052
ty::ConstKind::Param(p) => p.visit_with(visitor),
1053-
ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
1053+
ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
10541054
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
10551055
false
10561056
}

src/librustc/ty/sty.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::infer::canonical::Canonical;
99
use crate::middle::region;
1010
use crate::mir::interpret::ConstValue;
1111
use crate::mir::interpret::Scalar;
12+
use crate::mir::Promoted;
1213
use crate::ty::layout::VariantIdx;
1314
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
1415
use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
@@ -2375,7 +2376,7 @@ impl<'tcx> Const<'tcx> {
23752376

23762377
#[inline]
23772378
pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
2378-
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
2379+
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
23792380
let param_env_and_substs = param_env.with_reveal_all().and(substs);
23802381

23812382
// Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
@@ -2387,11 +2388,11 @@ impl<'tcx> Const<'tcx> {
23872388

23882389
// try to resolve e.g. associated constants to their definition on an impl, and then
23892390
// evaluate the const.
2390-
tcx.const_eval_resolve(param_env, did, substs, None).ok()
2391+
tcx.const_eval_resolve(param_env, did, substs, promoted, None).ok()
23912392
};
23922393

23932394
match self.val {
2394-
ConstKind::Unevaluated(did, substs) => {
2395+
ConstKind::Unevaluated(did, substs, promoted) => {
23952396
// HACK(eddyb) when substs contain e.g. inference variables,
23962397
// attempt using identity substs instead, that will succeed
23972398
// when the expression doesn't depend on any parameters.
@@ -2401,12 +2402,12 @@ impl<'tcx> Const<'tcx> {
24012402
let identity_substs = InternalSubsts::identity_for_item(tcx, did);
24022403
// The `ParamEnv` needs to match the `identity_substs`.
24032404
let identity_param_env = tcx.param_env(did);
2404-
match try_const_eval(did, identity_param_env, identity_substs) {
2405+
match try_const_eval(did, identity_param_env, identity_substs, promoted) {
24052406
Some(ct) => ct.subst(tcx, substs),
24062407
None => self,
24072408
}
24082409
} else {
2409-
try_const_eval(did, param_env, substs).unwrap_or(self)
2410+
try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
24102411
}
24112412
}
24122413
_ => self,
@@ -2470,7 +2471,7 @@ pub enum ConstKind<'tcx> {
24702471

24712472
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
24722473
/// variants when the code is monomorphic enough for that.
2473-
Unevaluated(DefId, SubstsRef<'tcx>),
2474+
Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
24742475

24752476
/// Used to hold computed value.
24762477
Value(ConstValue<'tcx>),

src/librustc/ty/walk.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
8181
| ty::Bound(..)
8282
| ty::Foreign(..) => {}
8383
ty::Array(ty, len) => {
84-
if let ty::ConstKind::Unevaluated(_, substs) = len.val {
84+
if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
85+
assert!(promoted.is_none());
8586
stack.extend(substs.types().rev());
8687
}
8788
stack.push(len.ty);

src/librustc_codegen_ssa/mir/constant.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
2020
// use `get_static` to get at their id.
2121
// FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
2222
// always produce `&STATIC`. This may also simplify how const eval works with statics.
23-
ty::ConstKind::Unevaluated(def_id, substs) if self.cx.tcx().is_static(def_id) => {
23+
ty::ConstKind::Unevaluated(def_id, substs, promoted)
24+
if self.cx.tcx().is_static(def_id) =>
25+
{
26+
assert!(promoted.is_none());
2427
assert!(substs.is_empty(), "we don't support generic statics yet");
2528
let static_ = bx.get_static(def_id);
2629
// 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> {
4043
constant: &mir::Constant<'tcx>,
4144
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
4245
match constant.literal.val {
43-
ty::ConstKind::Unevaluated(def_id, substs) => {
46+
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
4447
let substs = self.monomorphize(&substs);
4548
self.cx
4649
.tcx()
47-
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
50+
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
4851
.map_err(|err| {
4952
self.cx
5053
.tcx()

src/librustc_mir/borrow_check/type_check/mod.rs

+48-11
Original file line numberDiff line numberDiff line change
@@ -310,17 +310,54 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
310310
);
311311
}
312312
} else {
313-
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
314-
if let Err(terr) = self.cx.fully_perform_op(
315-
location.to_locations(),
316-
ConstraintCategory::Boring,
317-
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
318-
constant.literal.ty,
319-
def_id,
320-
UserSubsts { substs, user_self_ty: None },
321-
)),
322-
) {
323-
span_mirbug!(self, constant, "bad constant type {:?} ({:?})", constant, terr);
313+
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
314+
if let Some(promoted) = promoted {
315+
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
316+
promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
317+
ty,
318+
san_ty| {
319+
if let Err(terr) = verifier.cx.eq_types(
320+
san_ty,
321+
ty,
322+
location.to_locations(),
323+
ConstraintCategory::Boring,
324+
) {
325+
span_mirbug!(
326+
verifier,
327+
promoted,
328+
"bad promoted type ({:?}: {:?}): {:?}",
329+
ty,
330+
san_ty,
331+
terr
332+
);
333+
};
334+
};
335+
336+
if !self.errors_reported {
337+
let promoted_body = self.promoted[promoted];
338+
self.sanitize_promoted(promoted_body, location);
339+
340+
let promoted_ty = promoted_body.return_ty();
341+
check_err(self, &promoted_body, ty, promoted_ty);
342+
}
343+
} else {
344+
if let Err(terr) = self.cx.fully_perform_op(
345+
location.to_locations(),
346+
ConstraintCategory::Boring,
347+
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
348+
constant.literal.ty,
349+
def_id,
350+
UserSubsts { substs, user_self_ty: None },
351+
)),
352+
) {
353+
span_mirbug!(
354+
self,
355+
constant,
356+
"bad constant type {:?} ({:?})",
357+
constant,
358+
terr
359+
);
360+
}
324361
}
325362
}
326363
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {

src/librustc_mir/const_eval.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub(crate) fn const_caller_location<'tcx>(
5252

5353
let loc_ty = tcx.caller_location_ty();
5454
let loc_place = ecx.alloc_caller_location(file, line, col);
55-
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
55+
intern_const_alloc_recursive(&mut ecx, None, loc_place, false).unwrap();
5656
let loc_const = ty::Const {
5757
ty: loc_ty,
5858
val: ty::ConstKind::Value(ConstValue::Scalar(loc_place.ptr.into())),

src/librustc_mir/const_eval/eval_queries.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ fn eval_body_using_ecx<'mir, 'tcx>(
5656
ecx.run()?;
5757

5858
// Intern the result
59-
intern_const_alloc_recursive(ecx, tcx.static_mutability(cid.instance.def_id()), ret)?;
59+
intern_const_alloc_recursive(
60+
ecx,
61+
tcx.static_mutability(cid.instance.def_id()),
62+
ret,
63+
body.ignore_interior_mut_in_const_validation,
64+
)?;
6065

6166
debug!("eval_body_using_ecx done: {:?}", *ret);
6267
Ok(ret)
@@ -171,9 +176,14 @@ fn validate_and_turn_into_const<'tcx>(
171176
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env, is_static);
172177
let val = (|| {
173178
let mplace = ecx.raw_const_to_mplace(constant)?;
174-
let mut ref_tracking = RefTracking::new(mplace);
175-
while let Some((mplace, path)) = ref_tracking.todo.pop() {
176-
ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
179+
180+
// FIXME do not validate promoteds until a decision on
181+
// https://github.com/rust-lang/rust/issues/67465 is made
182+
if cid.promoted.is_none() {
183+
let mut ref_tracking = RefTracking::new(mplace);
184+
while let Some((mplace, path)) = ref_tracking.todo.pop() {
185+
ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
186+
}
177187
}
178188
// Now that we validated, turn this into a proper constant.
179189
// Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides

0 commit comments

Comments
 (0)