Skip to content

Commit 3b93d71

Browse files
committed
Handle type annotations in promoted MIR correctly
Type annotations are shared between the MIR of a function and the promoted constants for that function, so keep them in the type checker when we check the promoted MIR.
1 parent 848c252 commit 3b93d71

File tree

3 files changed

+46
-15
lines changed

3 files changed

+46
-15
lines changed

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ use rustc::ty::fold::TypeFoldable;
3939
use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts};
4040
use rustc::ty::{
4141
self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType,
42-
CanonicalUserTypeAnnotation, UserTypeAnnotationIndex,
42+
CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
43+
UserTypeAnnotationIndex,
4344
};
4445
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
4546
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -283,7 +284,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
283284
location.to_locations(),
284285
ConstraintCategory::Boring,
285286
) {
286-
let annotation = &self.mir.user_type_annotations[annotation_index];
287+
let annotation = &self.cx.user_type_annotations[annotation_index];
287288
span_mirbug!(
288289
self,
289290
constant,
@@ -550,8 +551,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
550551
// checker on the promoted MIR, then transfer the constraints back to
551552
// the main MIR, changing the locations to the provided location.
552553

553-
let main_mir = mem::replace(&mut self.mir, promoted_mir);
554-
self.cx.mir = promoted_mir;
554+
let parent_mir = mem::replace(&mut self.mir, promoted_mir);
555555

556556
let all_facts = &mut None;
557557
let mut constraints = Default::default();
@@ -573,8 +573,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
573573
self.cx.typeck_mir(promoted_mir);
574574
}
575575

576-
self.mir = main_mir;
577-
self.cx.mir = main_mir;
576+
self.mir = parent_mir;
578577
// Merge the outlives constraints back in, at the given location.
579578
if let Some(ref mut base_bcx) = self.cx.borrowck_context {
580579
mem::swap(base_bcx.all_facts, all_facts);
@@ -818,7 +817,9 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
818817
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
819818
param_env: ty::ParamEnv<'gcx>,
820819
last_span: Span,
821-
mir: &'a Mir<'tcx>,
820+
/// User type annotations are shared between the main MIR and the MIR of
821+
/// all of the promoted items.
822+
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
822823
mir_def_id: DefId,
823824
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
824825
implicit_region_bound: Option<ty::Region<'tcx>>,
@@ -973,8 +974,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
973974
let mut checker = Self {
974975
infcx,
975976
last_span: DUMMY_SP,
976-
mir,
977977
mir_def_id,
978+
user_type_annotations: &mir.user_type_annotations,
978979
param_env,
979980
region_bound_pairs,
980981
implicit_region_bound,
@@ -990,9 +991,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
990991
fn check_user_type_annotations(&mut self) {
991992
debug!(
992993
"check_user_type_annotations: user_type_annotations={:?}",
993-
self.mir.user_type_annotations
994+
self.user_type_annotations
994995
);
995-
for user_annotation in &self.mir.user_type_annotations {
996+
for user_annotation in self.user_type_annotations {
996997
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
997998
let (annotation, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
998999
span, user_ty
@@ -1175,7 +1176,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11751176
a, v, user_ty, locations,
11761177
);
11771178

1178-
let annotated_type = self.mir.user_type_annotations[user_ty.base].inferred_ty;
1179+
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
11791180
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
11801181

11811182
let tcx = self.infcx.tcx;
@@ -1361,7 +1362,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
13611362
location.to_locations(),
13621363
ConstraintCategory::Boring,
13631364
) {
1364-
let annotation = &mir.user_type_annotations[annotation_index];
1365+
let annotation = &self.user_type_annotations[annotation_index];
13651366
span_mirbug!(
13661367
self,
13671368
stmt,
@@ -1420,7 +1421,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
14201421
Locations::All(stmt.source_info.span),
14211422
ConstraintCategory::TypeAnnotation,
14221423
) {
1423-
let annotation = &mir.user_type_annotations[projection.base];
1424+
let annotation = &self.user_type_annotations[projection.base];
14241425
span_mirbug!(
14251426
self,
14261427
stmt,
@@ -2078,7 +2079,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
20782079
}
20792080

20802081
Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
2081-
self.add_reborrow_constraint(location, region, borrowed_place);
2082+
self.add_reborrow_constraint(mir, location, region, borrowed_place);
20822083
}
20832084

20842085
// FIXME: These other cases have to be implemented in future PRs
@@ -2177,6 +2178,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
21772178
/// - `borrowed_place`: the place `P` being borrowed
21782179
fn add_reborrow_constraint(
21792180
&mut self,
2181+
mir: &Mir<'tcx>,
21802182
location: Location,
21812183
borrow_region: ty::Region<'tcx>,
21822184
borrowed_place: &Place<'tcx>,
@@ -2226,7 +2228,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
22262228
match *elem {
22272229
ProjectionElem::Deref => {
22282230
let tcx = self.infcx.tcx;
2229-
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
2231+
let base_ty = base.ty(mir, tcx).to_ty(tcx);
22302232

22312233
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
22322234
match base_ty.sty {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Test that type annotations are checked in promoted constants correctly.
2+
3+
#![feature(nll)]
4+
5+
fn foo<'a>() {
6+
let x = 0;
7+
let f = &drop::<&'a i32>;
8+
f(&x);
9+
//~^ ERROR `x` does not live long enough
10+
}
11+
12+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0597]: `x` does not live long enough
2+
--> $DIR/promoted-annotation.rs:8:7
3+
|
4+
LL | fn foo<'a>() {
5+
| -- lifetime `'a` defined here
6+
LL | let x = 0;
7+
LL | let f = &drop::<&'a i32>;
8+
| ---------------- assignment requires that `x` is borrowed for `'a`
9+
LL | f(&x);
10+
| ^^ borrowed value does not live long enough
11+
LL | //~^ ERROR `x` does not live long enough
12+
LL | }
13+
| - `x` dropped here while still borrowed
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)