Skip to content

Commit ff055e2

Browse files
committed
Ensure closure requirements are proven for inline const
1 parent 1d32b20 commit ff055e2

File tree

3 files changed

+127
-5
lines changed

3 files changed

+127
-5
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+79-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1010
use rustc_data_structures::vec_map::VecMap;
1111
use rustc_errors::struct_span_err;
1212
use rustc_hir as hir;
13+
use rustc_hir::def::DefKind;
1314
use rustc_hir::def_id::LocalDefId;
1415
use rustc_hir::lang_items::LangItem;
1516
use rustc_index::vec::{Idx, IndexVec};
@@ -1532,6 +1533,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
15321533
}
15331534
}
15341535
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
1536+
self.check_operand(discr, term_location);
1537+
15351538
let discr_ty = discr.ty(body, tcx);
15361539
if let Err(terr) = self.sub_types(
15371540
discr_ty,
@@ -1554,6 +1557,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
15541557
// FIXME: check the values
15551558
}
15561559
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
1560+
self.check_operand(func, term_location);
1561+
for arg in args {
1562+
self.check_operand(arg, term_location);
1563+
}
1564+
15571565
let func_ty = func.ty(body, tcx);
15581566
debug!("check_terminator: call, func_ty={:?}", func_ty);
15591567
let sig = match func_ty.kind() {
@@ -1598,6 +1606,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
15981606
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
15991607
}
16001608
TerminatorKind::Assert { ref cond, ref msg, .. } => {
1609+
self.check_operand(cond, term_location);
1610+
16011611
let cond_ty = cond.ty(body, tcx);
16021612
if cond_ty != tcx.types.bool {
16031613
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
@@ -1613,6 +1623,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16131623
}
16141624
}
16151625
TerminatorKind::Yield { ref value, .. } => {
1626+
self.check_operand(value, term_location);
1627+
16161628
let value_ty = value.ty(body, tcx);
16171629
match body.yield_ty() {
16181630
None => span_mirbug!(self, term, "yield in non-generator"),
@@ -1941,15 +1953,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19411953
}
19421954
}
19431955

1956+
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
1957+
if let Operand::Constant(constant) = op {
1958+
let maybe_uneval = match constant.literal {
1959+
ConstantKind::Ty(ct) => match ct.val {
1960+
ty::ConstKind::Unevaluated(uv) => Some(uv),
1961+
_ => None,
1962+
},
1963+
_ => None,
1964+
};
1965+
if let Some(uv) = maybe_uneval {
1966+
if uv.promoted.is_none() {
1967+
let tcx = self.tcx();
1968+
let def_id = uv.def.def_id_for_type_of();
1969+
if tcx.def_kind(def_id) == DefKind::InlineConst {
1970+
let predicates = self.prove_closure_bounds(
1971+
tcx,
1972+
def_id.expect_local(),
1973+
uv.substs(tcx),
1974+
location,
1975+
);
1976+
self.normalize_and_prove_instantiated_predicates(
1977+
def_id,
1978+
predicates,
1979+
location.to_locations(),
1980+
);
1981+
}
1982+
}
1983+
}
1984+
}
1985+
}
1986+
19441987
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
19451988
let tcx = self.tcx();
19461989

19471990
match rvalue {
19481991
Rvalue::Aggregate(ak, ops) => {
1992+
for op in ops {
1993+
self.check_operand(op, location);
1994+
}
19491995
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
19501996
}
19511997

19521998
Rvalue::Repeat(operand, len) => {
1999+
self.check_operand(operand, location);
2000+
19532001
// If the length cannot be evaluated we must assume that the length can be larger
19542002
// than 1.
19552003
// If the length is larger than 1, the repeat expression will need to copy the
@@ -2000,7 +2048,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20002048
}
20012049
}
20022050

2003-
Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
2051+
Rvalue::NullaryOp(_, ty) => {
2052+
let trait_ref = ty::TraitRef {
2053+
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
2054+
substs: tcx.mk_substs_trait(ty, &[]),
2055+
};
2056+
2057+
self.prove_trait_ref(
2058+
trait_ref,
2059+
location.to_locations(),
2060+
ConstraintCategory::SizedBound,
2061+
);
2062+
}
2063+
2064+
Rvalue::ShallowInitBox(operand, ty) => {
2065+
self.check_operand(operand, location);
2066+
20042067
let trait_ref = ty::TraitRef {
20052068
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
20062069
substs: tcx.mk_substs_trait(ty, &[]),
@@ -2014,6 +2077,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
20142077
}
20152078

20162079
Rvalue::Cast(cast_kind, op, ty) => {
2080+
self.check_operand(op, location);
2081+
20172082
match cast_kind {
20182083
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
20192084
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
@@ -2260,6 +2325,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
22602325
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
22612326
box (left, right),
22622327
) => {
2328+
self.check_operand(left, location);
2329+
self.check_operand(right, location);
2330+
22632331
let ty_left = left.ty(body, tcx);
22642332
match ty_left.kind() {
22652333
// Types with regions are comparable if they have a common super-type.
@@ -2310,13 +2378,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23102378
}
23112379
}
23122380

2381+
Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
2382+
self.check_operand(operand, location);
2383+
}
2384+
2385+
Rvalue::BinaryOp(_, box (left, right))
2386+
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
2387+
self.check_operand(left, location);
2388+
self.check_operand(right, location);
2389+
}
2390+
23132391
Rvalue::AddressOf(..)
23142392
| Rvalue::ThreadLocalRef(..)
2315-
| Rvalue::Use(..)
23162393
| Rvalue::Len(..)
2317-
| Rvalue::BinaryOp(..)
2318-
| Rvalue::CheckedBinaryOp(..)
2319-
| Rvalue::UnaryOp(..)
23202394
| Rvalue::Discriminant(..) => {}
23212395
}
23222396
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![allow(incomplete_features)]
2+
#![feature(const_mut_refs)]
3+
#![feature(inline_const)]
4+
5+
use std::marker::PhantomData;
6+
7+
#[derive(PartialEq, Eq)]
8+
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
9+
10+
impl<'a, T: ?Sized> InvariantRef<'a, T> {
11+
pub const fn new(r: &'a T) -> Self {
12+
InvariantRef(r, PhantomData)
13+
}
14+
}
15+
16+
impl<'a> InvariantRef<'a, ()> {
17+
pub const NEW: Self = InvariantRef::new(&());
18+
}
19+
20+
fn equate<T>(x: T, y: T){}
21+
22+
fn foo<'a>() {
23+
let y = ();
24+
equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
25+
//~^ ERROR `y` does not live long enough [E0597]
26+
}
27+
28+
fn main() {
29+
foo();
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0597]: `y` does not live long enough
2+
--> $DIR/const-expr-lifetime-err.rs:24:30
3+
|
4+
LL | fn foo<'a>() {
5+
| -- lifetime `'a` defined here
6+
LL | let y = ();
7+
LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
8+
| ------------------^^-
9+
| | |
10+
| | borrowed value does not live long enough
11+
| argument requires that `y` is borrowed for `'a`
12+
LL |
13+
LL | }
14+
| - `y` dropped here while still borrowed
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)