Skip to content

Commit 87e6a37

Browse files
committed
Promote Refs to constants instead of static
1 parent d2ad810 commit 87e6a37

Some content is hidden

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

44 files changed

+402
-215
lines changed

src/librustc/mir/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ pub struct Body<'tcx> {
154154

155155
/// A span representing this MIR, for error reporting.
156156
pub span: Span,
157+
158+
/// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
159+
/// we'd statically know that no thing with interior mutability will ever be available to the
160+
/// user without some serious unsafe code. Now this means that our promoted is actually
161+
/// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
162+
/// index may be a runtime value. Such a promoted value is illegal because it has reachable
163+
/// interior mutability. This flag just makes this situation very obvious where the previous
164+
/// implementation without the flag hid this situation silently.
165+
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
166+
pub ignore_interior_mut_in_const_validation: bool,
157167
}
158168

159169
impl<'tcx> Body<'tcx> {
@@ -190,6 +200,7 @@ impl<'tcx> Body<'tcx> {
190200
spread_arg: None,
191201
var_debug_info,
192202
span,
203+
ignore_interior_mut_in_const_validation: false,
193204
control_flow_destroyed,
194205
}
195206
}

src/librustc/ty/flags.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl FlagComputation {
231231
fn add_const(&mut self, c: &ty::Const<'_>) {
232232
self.add_ty(c.ty);
233233
match c.val {
234-
ty::ConstKind::Unevaluated(_, substs) => {
234+
ty::ConstKind::Unevaluated(_, substs, _) => {
235235
self.add_substs(substs);
236236
self.add_flags(TypeFlags::HAS_PROJECTION);
237237
},

src/librustc/ty/print/pretty.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -891,21 +891,26 @@ pub trait PrettyPrinter<'tcx>:
891891

892892
match (ct.val, &ct.ty.kind) {
893893
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
894-
(ty::ConstKind::Unevaluated(did, substs), _) => {
895-
match self.tcx().def_kind(did) {
896-
| Some(DefKind::Static)
897-
| Some(DefKind::Const)
898-
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
899-
_ => if did.is_local() {
900-
let span = self.tcx().def_span(did);
901-
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
902-
p!(write("{}", snip))
894+
(ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
895+
if let Some(promoted) = promoted {
896+
p!(print_value_path(did, substs));
897+
p!(write("::{:?}", promoted));
898+
} else {
899+
match self.tcx().def_kind(did) {
900+
| Some(DefKind::Static)
901+
| Some(DefKind::Const)
902+
| Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
903+
_ => if did.is_local() {
904+
let span = self.tcx().def_span(did);
905+
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
906+
p!(write("{}", snip))
907+
} else {
908+
p!(write("_: "), print(ct.ty))
909+
}
903910
} else {
904911
p!(write("_: "), print(ct.ty))
905-
}
906-
} else {
907-
p!(write("_: "), print(ct.ty))
908-
},
912+
},
913+
}
909914
}
910915
},
911916
(ty::ConstKind::Infer(..), _) => p!(write("_: "), print(ct.ty)),

src/librustc/ty/relate.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,13 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
603603
},
604604

605605
// FIXME(const_generics): this is wrong, as it is a projection
606-
(ty::ConstKind::Unevaluated(a_def_id, a_substs),
607-
ty::ConstKind::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => {
606+
(
607+
ty::ConstKind::Unevaluated(a_def_id, a_substs, a_promoted),
608+
ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted),
609+
) if a_def_id == b_def_id && a_promoted == b_promoted => {
608610
let substs =
609611
relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
610-
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs))
612+
Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted))
611613
}
612614
_ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
613615
};

src/librustc/ty/structural_impls.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,8 +1172,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
11721172
match *self {
11731173
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
11741174
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
1175-
ty::ConstKind::Unevaluated(did, substs)
1176-
=> ty::ConstKind::Unevaluated(did, substs.fold_with(folder)),
1175+
ty::ConstKind::Unevaluated(did, substs, promoted)
1176+
=> ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted),
11771177
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..)
11781178
| ty::ConstKind::Placeholder(..) => *self,
11791179
}
@@ -1183,7 +1183,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
11831183
match *self {
11841184
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
11851185
ty::ConstKind::Param(p) => p.visit_with(visitor),
1186-
ty::ConstKind::Unevaluated(_, substs) => substs.visit_with(visitor),
1186+
ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
11871187
ty::ConstKind::Value(_) | ty::ConstKind::Bound(..)
11881188
| ty::ConstKind::Placeholder(_) => false,
11891189
}

src/librustc/ty/sty.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use self::TyKind::*;
88
use crate::hir;
99
use crate::hir::def_id::DefId;
1010
use crate::infer::canonical::Canonical;
11+
use crate::mir::Promoted;
1112
use crate::mir::interpret::ConstValue;
1213
use crate::middle::region;
1314
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind};
@@ -2330,7 +2331,7 @@ impl<'tcx> Const<'tcx> {
23302331
tcx: TyCtxt<'tcx>,
23312332
param_env: ParamEnv<'tcx>,
23322333
) -> &Const<'tcx> {
2333-
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
2334+
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs, promoted| {
23342335
let param_env_and_substs = param_env.with_reveal_all().and(substs);
23352336

23362337
// Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
@@ -2344,13 +2345,13 @@ impl<'tcx> Const<'tcx> {
23442345
let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
23452346
let gid = GlobalId {
23462347
instance,
2347-
promoted: None,
2348+
promoted,
23482349
};
23492350
tcx.const_eval(param_env.and(gid)).ok()
23502351
};
23512352

23522353
match self.val {
2353-
ConstKind::Unevaluated(did, substs) => {
2354+
ConstKind::Unevaluated(did, substs, promoted) => {
23542355
// HACK(eddyb) when substs contain e.g. inference variables,
23552356
// attempt using identity substs instead, that will succeed
23562357
// when the expression doesn't depend on any parameters.
@@ -2360,12 +2361,12 @@ impl<'tcx> Const<'tcx> {
23602361
let identity_substs = InternalSubsts::identity_for_item(tcx, did);
23612362
// The `ParamEnv` needs to match the `identity_substs`.
23622363
let identity_param_env = tcx.param_env(did);
2363-
match try_const_eval(did, identity_param_env, identity_substs) {
2364+
match try_const_eval(did, identity_param_env, identity_substs, promoted) {
23642365
Some(ct) => ct.subst(tcx, substs),
23652366
None => self,
23662367
}
23672368
} else {
2368-
try_const_eval(did, param_env, substs).unwrap_or(self)
2369+
try_const_eval(did, param_env, substs, promoted).unwrap_or(self)
23692370
}
23702371
},
23712372
_ => self,
@@ -2418,7 +2419,7 @@ pub enum ConstKind<'tcx> {
24182419

24192420
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
24202421
/// variants when the code is monomorphic enough for that.
2421-
Unevaluated(DefId, SubstsRef<'tcx>),
2422+
Unevaluated(DefId, SubstsRef<'tcx>, Option<Promoted>),
24222423

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

src/librustc/ty/walk.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
7474
ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => {
7575
}
7676
ty::Array(ty, len) => {
77-
if let ty::ConstKind::Unevaluated(_, substs) = len.val {
77+
if let ty::ConstKind::Unevaluated(_, substs, promoted) = len.val {
78+
assert!(promoted.is_none());
7879
stack.extend(substs.types().rev());
7980
}
8081
stack.push(len.ty);

src/librustc/ty/wf.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
362362
/// Pushes the obligations required for an array length to be WF
363363
/// into `self.out`.
364364
fn compute_array_len(&mut self, constant: ty::Const<'tcx>) {
365-
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.val {
365+
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val {
366+
assert!(promoted.is_none());
367+
366368
let obligations = self.nominal_obligations(def_id, substs);
367369
self.out.extend(obligations);
368370

src/librustc_codegen_ssa/mir/constant.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ 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)
23+
ty::ConstKind::Unevaluated(def_id, substs, promoted)
2424
if self.cx.tcx().is_static(def_id) => {
25+
assert!(promoted.is_none());
2526
assert!(substs.is_empty(), "we don't support generic statics yet");
2627
let static_ = bx.get_static(def_id);
2728
// we treat operands referring to statics as if they were `&STATIC` instead
@@ -41,17 +42,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
4142
constant: &mir::Constant<'tcx>,
4243
) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> {
4344
match constant.literal.val {
44-
ty::ConstKind::Unevaluated(def_id, substs) => {
45+
ty::ConstKind::Unevaluated(def_id, substs, promoted) => {
4546
let substs = self.monomorphize(&substs);
4647
let instance = ty::Instance::resolve(
4748
self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs,
4849
).unwrap();
4950
let cid = mir::interpret::GlobalId {
5051
instance,
51-
promoted: None,
52+
promoted,
5253
};
5354
self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| {
54-
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
55+
if promoted.is_none() {
56+
self.cx
57+
.tcx()
58+
.sess
59+
.span_err(constant.span, "erroneous constant encountered");
60+
}
5561
err
5662
})
5763
},

src/librustc_mir/borrow_check/type_check/mod.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -326,21 +326,53 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
326326
);
327327
}
328328
} else {
329-
if let ty::ConstKind::Unevaluated(def_id, substs) = constant.literal.val {
330-
if let Err(terr) = self.cx.fully_perform_op(
331-
location.to_locations(),
332-
ConstraintCategory::Boring,
333-
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
334-
constant.literal.ty, def_id, UserSubsts { substs, user_self_ty: None },
335-
)),
336-
) {
337-
span_mirbug!(
338-
self,
339-
constant,
340-
"bad constant type {:?} ({:?})",
341-
constant,
342-
terr
343-
);
329+
if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.literal.val {
330+
if let Some(promoted) = promoted {
331+
let check_err =
332+
|verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
333+
promoted: &ReadOnlyBodyAndCache<'_, 'tcx>,
334+
ty,
335+
san_ty| {
336+
if let Err(terr) = verifier.cx.eq_types(
337+
san_ty,
338+
ty,
339+
location.to_locations(),
340+
ConstraintCategory::Boring,
341+
) {
342+
span_mirbug!(
343+
verifier,
344+
promoted,
345+
"bad promoted type ({:?}: {:?}): {:?}",
346+
ty,
347+
san_ty,
348+
terr
349+
);
350+
};
351+
};
352+
353+
if !self.errors_reported {
354+
let promoted_body = self.promoted[promoted];
355+
self.sanitize_promoted(promoted_body, location);
356+
357+
let promoted_ty = promoted_body.return_ty();
358+
check_err(self, &promoted_body, ty, promoted_ty);
359+
}
360+
} else {
361+
if let Err(terr) = self.cx.fully_perform_op(
362+
location.to_locations(),
363+
ConstraintCategory::Boring,
364+
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
365+
constant.literal.ty, def_id, UserSubsts { substs, user_self_ty: None },
366+
)),
367+
) {
368+
span_mirbug!(
369+
self,
370+
constant,
371+
"bad constant type {:?} ({:?})",
372+
constant,
373+
terr
374+
);
375+
}
344376
}
345377
}
346378
if let ty::FnDef(def_id, substs) = constant.literal.ty.kind {

0 commit comments

Comments
 (0)