Ensure closure requirements are proven for inline const
This commit is contained in:
parent
1d32b20170
commit
ff055e2135
3 changed files with 127 additions and 5 deletions
|
@ -10,6 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::vec_map::VecMap;
|
use rustc_data_structures::vec_map::VecMap;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
@ -1532,6 +1533,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
|
||||||
|
self.check_operand(discr, term_location);
|
||||||
|
|
||||||
let discr_ty = discr.ty(body, tcx);
|
let discr_ty = discr.ty(body, tcx);
|
||||||
if let Err(terr) = self.sub_types(
|
if let Err(terr) = self.sub_types(
|
||||||
discr_ty,
|
discr_ty,
|
||||||
|
@ -1554,6 +1557,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
// FIXME: check the values
|
// FIXME: check the values
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
|
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
|
||||||
|
self.check_operand(func, term_location);
|
||||||
|
for arg in args {
|
||||||
|
self.check_operand(arg, term_location);
|
||||||
|
}
|
||||||
|
|
||||||
let func_ty = func.ty(body, tcx);
|
let func_ty = func.ty(body, tcx);
|
||||||
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
debug!("check_terminator: call, func_ty={:?}", func_ty);
|
||||||
let sig = match func_ty.kind() {
|
let sig = match func_ty.kind() {
|
||||||
|
@ -1598,6 +1606,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
|
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { ref cond, ref msg, .. } => {
|
TerminatorKind::Assert { ref cond, ref msg, .. } => {
|
||||||
|
self.check_operand(cond, term_location);
|
||||||
|
|
||||||
let cond_ty = cond.ty(body, tcx);
|
let cond_ty = cond.ty(body, tcx);
|
||||||
if cond_ty != tcx.types.bool {
|
if cond_ty != tcx.types.bool {
|
||||||
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
|
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
|
||||||
|
@ -1613,6 +1623,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Yield { ref value, .. } => {
|
TerminatorKind::Yield { ref value, .. } => {
|
||||||
|
self.check_operand(value, term_location);
|
||||||
|
|
||||||
let value_ty = value.ty(body, tcx);
|
let value_ty = value.ty(body, tcx);
|
||||||
match body.yield_ty() {
|
match body.yield_ty() {
|
||||||
None => span_mirbug!(self, term, "yield in non-generator"),
|
None => span_mirbug!(self, term, "yield in non-generator"),
|
||||||
|
@ -1941,15 +1953,51 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||||
|
if let Operand::Constant(constant) = op {
|
||||||
|
let maybe_uneval = match constant.literal {
|
||||||
|
ConstantKind::Ty(ct) => match ct.val {
|
||||||
|
ty::ConstKind::Unevaluated(uv) => Some(uv),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(uv) = maybe_uneval {
|
||||||
|
if uv.promoted.is_none() {
|
||||||
|
let tcx = self.tcx();
|
||||||
|
let def_id = uv.def.def_id_for_type_of();
|
||||||
|
if tcx.def_kind(def_id) == DefKind::InlineConst {
|
||||||
|
let predicates = self.prove_closure_bounds(
|
||||||
|
tcx,
|
||||||
|
def_id.expect_local(),
|
||||||
|
uv.substs(tcx),
|
||||||
|
location,
|
||||||
|
);
|
||||||
|
self.normalize_and_prove_instantiated_predicates(
|
||||||
|
def_id,
|
||||||
|
predicates,
|
||||||
|
location.to_locations(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
|
|
||||||
match rvalue {
|
match rvalue {
|
||||||
Rvalue::Aggregate(ak, ops) => {
|
Rvalue::Aggregate(ak, ops) => {
|
||||||
|
for op in ops {
|
||||||
|
self.check_operand(op, location);
|
||||||
|
}
|
||||||
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
|
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Repeat(operand, len) => {
|
Rvalue::Repeat(operand, len) => {
|
||||||
|
self.check_operand(operand, location);
|
||||||
|
|
||||||
// If the length cannot be evaluated we must assume that the length can be larger
|
// If the length cannot be evaluated we must assume that the length can be larger
|
||||||
// than 1.
|
// than 1.
|
||||||
// If the length is larger than 1, the repeat expression will need to copy the
|
// 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> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
|
Rvalue::NullaryOp(_, ty) => {
|
||||||
|
let trait_ref = ty::TraitRef {
|
||||||
|
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||||
|
substs: tcx.mk_substs_trait(ty, &[]),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.prove_trait_ref(
|
||||||
|
trait_ref,
|
||||||
|
location.to_locations(),
|
||||||
|
ConstraintCategory::SizedBound,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rvalue::ShallowInitBox(operand, ty) => {
|
||||||
|
self.check_operand(operand, location);
|
||||||
|
|
||||||
let trait_ref = ty::TraitRef {
|
let trait_ref = ty::TraitRef {
|
||||||
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
|
||||||
substs: tcx.mk_substs_trait(ty, &[]),
|
substs: tcx.mk_substs_trait(ty, &[]),
|
||||||
|
@ -2014,6 +2077,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rvalue::Cast(cast_kind, op, ty) => {
|
Rvalue::Cast(cast_kind, op, ty) => {
|
||||||
|
self.check_operand(op, location);
|
||||||
|
|
||||||
match cast_kind {
|
match cast_kind {
|
||||||
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
|
||||||
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
|
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
|
||||||
|
@ -2260,6 +2325,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
|
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
|
||||||
box (left, right),
|
box (left, right),
|
||||||
) => {
|
) => {
|
||||||
|
self.check_operand(left, location);
|
||||||
|
self.check_operand(right, location);
|
||||||
|
|
||||||
let ty_left = left.ty(body, tcx);
|
let ty_left = left.ty(body, tcx);
|
||||||
match ty_left.kind() {
|
match ty_left.kind() {
|
||||||
// Types with regions are comparable if they have a common super-type.
|
// Types with regions are comparable if they have a common super-type.
|
||||||
|
@ -2310,13 +2378,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
|
||||||
|
self.check_operand(operand, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rvalue::BinaryOp(_, box (left, right))
|
||||||
|
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
|
||||||
|
self.check_operand(left, location);
|
||||||
|
self.check_operand(right, location);
|
||||||
|
}
|
||||||
|
|
||||||
Rvalue::AddressOf(..)
|
Rvalue::AddressOf(..)
|
||||||
| Rvalue::ThreadLocalRef(..)
|
| Rvalue::ThreadLocalRef(..)
|
||||||
| Rvalue::Use(..)
|
|
||||||
| Rvalue::Len(..)
|
| Rvalue::Len(..)
|
||||||
| Rvalue::BinaryOp(..)
|
|
||||||
| Rvalue::CheckedBinaryOp(..)
|
|
||||||
| Rvalue::UnaryOp(..)
|
|
||||||
| Rvalue::Discriminant(..) => {}
|
| Rvalue::Discriminant(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/test/ui/inline-const/const-expr-lifetime-err.rs
Normal file
30
src/test/ui/inline-const/const-expr-lifetime-err.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(const_mut_refs)]
|
||||||
|
#![feature(inline_const)]
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
|
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
|
||||||
|
|
||||||
|
impl<'a, T: ?Sized> InvariantRef<'a, T> {
|
||||||
|
pub const fn new(r: &'a T) -> Self {
|
||||||
|
InvariantRef(r, PhantomData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InvariantRef<'a, ()> {
|
||||||
|
pub const NEW: Self = InvariantRef::new(&());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equate<T>(x: T, y: T){}
|
||||||
|
|
||||||
|
fn foo<'a>() {
|
||||||
|
let y = ();
|
||||||
|
equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
|
||||||
|
//~^ ERROR `y` does not live long enough [E0597]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo();
|
||||||
|
}
|
18
src/test/ui/inline-const/const-expr-lifetime-err.stderr
Normal file
18
src/test/ui/inline-const/const-expr-lifetime-err.stderr
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
error[E0597]: `y` does not live long enough
|
||||||
|
--> $DIR/const-expr-lifetime-err.rs:24:30
|
||||||
|
|
|
||||||
|
LL | fn foo<'a>() {
|
||||||
|
| -- lifetime `'a` defined here
|
||||||
|
LL | let y = ();
|
||||||
|
LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
|
||||||
|
| ------------------^^-
|
||||||
|
| | |
|
||||||
|
| | borrowed value does not live long enough
|
||||||
|
| argument requires that `y` is borrowed for `'a`
|
||||||
|
LL |
|
||||||
|
LL | }
|
||||||
|
| - `y` dropped here while still borrowed
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0597`.
|
Loading…
Add table
Add a link
Reference in a new issue