Skip to content

Commit d049e5d

Browse files
committed
avoid type-live-for-region obligations on dummy nodes
Type-live-for-region obligations on DUMMY_NODE_ID cause an ICE, and it turns out that in the few cases they are needed, these obligations are not needed anyway because they are verified elsewhere. Fixes rust-lang#46069.
1 parent 2f47a9e commit d049e5d

File tree

7 files changed

+117
-30
lines changed

7 files changed

+117
-30
lines changed

src/librustc/infer/outlives/obligations.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
8888
body_id: ast::NodeId,
8989
obligation: RegionObligation<'tcx>,
9090
) {
91+
debug!("register_region_obligation({:?}, {:?})", body_id, obligation);
9192
self.region_obligations
9293
.borrow_mut()
9394
.push((body_id, obligation));

src/librustc/traits/fulfill.rs

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ pub struct FulfillmentContext<'tcx> {
4646
// A list of all obligations that have been registered with this
4747
// fulfillment context.
4848
predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
49+
// Should this fulfillment context register type-lives-for-region
50+
// obligations on its parent infcx? In some cases, region
51+
// obligations are either already known to hold (normalization) or
52+
// hopefully verifed elsewhere (type-impls-bound), and therefore
53+
// should not be checked.
54+
//
55+
// Note that if we are normalizing a type that we already
56+
// know is well-formed, there should be no harm setting this
57+
// to true - all the region variables should be determinable
58+
// using the RFC 447 rules, which don't depend on
59+
// type-lives-for-region constraints, and because the type
60+
// is well-formed, the constraints should hold.
61+
register_region_obligations: bool,
4962
}
5063

5164
#[derive(Clone, Debug)]
@@ -59,6 +72,14 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
5972
pub fn new() -> FulfillmentContext<'tcx> {
6073
FulfillmentContext {
6174
predicates: ObligationForest::new(),
75+
register_region_obligations: true
76+
}
77+
}
78+
79+
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
80+
FulfillmentContext {
81+
predicates: ObligationForest::new(),
82+
register_region_obligations: false
6283
}
6384
}
6485

@@ -191,7 +212,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
191212
debug!("select: starting another iteration");
192213

193214
// Process pending obligations.
194-
let outcome = self.predicates.process_obligations(&mut FulfillProcessor { selcx });
215+
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
216+
selcx,
217+
register_region_obligations: self.register_region_obligations
218+
});
195219
debug!("select: outcome={:?}", outcome);
196220

197221
// FIXME: if we kept the original cache key, we could mark projection
@@ -220,6 +244,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
220244

221245
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
222246
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
247+
register_region_obligations: bool
223248
}
224249

225250
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
@@ -230,7 +255,7 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
230255
obligation: &mut Self::Obligation)
231256
-> Result<Option<Vec<Self::Obligation>>, Self::Error>
232257
{
233-
process_predicate(self.selcx, obligation)
258+
process_predicate(self.selcx, obligation, self.register_region_obligations)
234259
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
235260
obligation: o,
236261
stalled_on: vec![]
@@ -269,7 +294,8 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't
269294
/// - `Err` if the predicate does not hold
270295
fn process_predicate<'a, 'gcx, 'tcx>(
271296
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
272-
pending_obligation: &mut PendingPredicateObligation<'tcx>)
297+
pending_obligation: &mut PendingPredicateObligation<'tcx>,
298+
register_region_obligations: bool)
273299
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
274300
FulfillmentErrorCode<'tcx>>
275301
{
@@ -391,26 +417,30 @@ fn process_predicate<'a, 'gcx, 'tcx>(
391417
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
392418
Some(t_a) => {
393419
let r_static = selcx.tcx().types.re_static;
394-
selcx.infcx().register_region_obligation(
395-
obligation.cause.body_id,
396-
RegionObligation {
397-
sup_type: t_a,
398-
sub_region: r_static,
399-
cause: obligation.cause.clone(),
400-
});
420+
if register_region_obligations {
421+
selcx.infcx().register_region_obligation(
422+
obligation.cause.body_id,
423+
RegionObligation {
424+
sup_type: t_a,
425+
sub_region: r_static,
426+
cause: obligation.cause.clone(),
427+
});
428+
}
401429
Ok(Some(vec![]))
402430
}
403431
}
404432
}
405433
// If there aren't, register the obligation.
406434
Some(ty::OutlivesPredicate(t_a, r_b)) => {
407-
selcx.infcx().register_region_obligation(
408-
obligation.cause.body_id,
409-
RegionObligation {
410-
sup_type: t_a,
411-
sub_region: r_b,
412-
cause: obligation.cause.clone()
413-
});
435+
if register_region_obligations {
436+
selcx.infcx().register_region_obligation(
437+
obligation.cause.body_id,
438+
RegionObligation {
439+
sup_type: t_a,
440+
sub_region: r_b,
441+
cause: obligation.cause.clone()
442+
});
443+
}
414444
Ok(Some(vec![]))
415445
}
416446
}

src/librustc/traits/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
431431
// this function's result remains infallible, we must confirm
432432
// that guess. While imperfect, I believe this is sound.
433433

434-
let mut fulfill_cx = FulfillmentContext::new();
434+
let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
435435

436436
// We can use a dummy node-id here because we won't pay any mind
437437
// to region obligations that arise (there shouldn't really be any
@@ -583,9 +583,6 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
583583
-> Result<T, Vec<FulfillmentError<'tcx>>>
584584
where T : TypeFoldable<'tcx>
585585
{
586-
debug!("fully_normalize(value={:?})", value);
587-
588-
let selcx = &mut SelectionContext::new(infcx);
589586
// FIXME (@jroesch) ISSUE 26721
590587
// I'm not sure if this is a bug or not, needs further investigation.
591588
// It appears that by reusing the fulfillment_cx here we incur more
@@ -599,8 +596,21 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
599596
//
600597
// I think we should probably land this refactor and then come
601598
// back to this is a follow-up patch.
602-
let mut fulfill_cx = FulfillmentContext::new();
599+
let fulfillcx = FulfillmentContext::new();
600+
fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value)
601+
}
603602

603+
pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
604+
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
605+
mut fulfill_cx: FulfillmentContext<'tcx>,
606+
cause: ObligationCause<'tcx>,
607+
param_env: ty::ParamEnv<'tcx>,
608+
value: &T)
609+
-> Result<T, Vec<FulfillmentError<'tcx>>>
610+
where T : TypeFoldable<'tcx>
611+
{
612+
debug!("fully_normalize_with_fulfillcx(value={:?})", value);
613+
let selcx = &mut SelectionContext::new(infcx);
604614
let Normalized { value: normalized_value, obligations } =
605615
project::normalize(selcx, param_env, cause, value);
606616
debug!("fully_normalize: normalized_value={:?} obligations={:?}",

src/librustc/traits/specialize/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
241241
// (which are packed up in penv)
242242

243243
infcx.save_and_restore_in_snapshot_flag(|infcx| {
244-
let mut fulfill_cx = FulfillmentContext::new();
244+
let mut fulfill_cx = FulfillmentContext::new_ignoring_regions();
245245
for oblig in obligations.into_iter() {
246246
fulfill_cx.register_predicate_obligation(&infcx, oblig);
247247
}

src/librustc/traits/structural_impls.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use traits;
1212
use traits::project::Normalized;
13-
use ty::{Lift, TyCtxt};
13+
use ty::{self, Lift, TyCtxt};
1414
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
1515

1616
use std::fmt;
@@ -28,9 +28,16 @@ impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
2828

2929
impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
3030
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31-
write!(f, "Obligation(predicate={:?},depth={})",
32-
self.predicate,
33-
self.recursion_depth)
31+
if ty::tls::with(|tcx| tcx.sess.verbose()) {
32+
write!(f, "Obligation(predicate={:?},cause={:?},depth={})",
33+
self.predicate,
34+
self.cause,
35+
self.recursion_depth)
36+
} else {
37+
write!(f, "Obligation(predicate={:?},depth={})",
38+
self.predicate,
39+
self.recursion_depth)
40+
}
3441
}
3542
}
3643

src/librustc_mir/transform/nll/constraint_generation.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,17 @@ impl<'cx, 'gcx, 'tcx> ConstraintGeneration<'cx, 'gcx, 'tcx> {
152152
// associated types and parameters). We need to normalize
153153
// associated types here and possibly recursively process.
154154
for ty in dtorck_types {
155-
// FIXME -- I think that this may disregard some region obligations
156-
// or something. Do we care? -nmatsakis
157155
let cause = ObligationCause::dummy();
158-
match traits::fully_normalize(self.infcx, cause, self.param_env, &ty) {
156+
// We know that our original `dropped_ty` is well-formed,
157+
// so region obligations resulting from this normalization
158+
// should always hold.
159+
//
160+
// Therefore we ignore them instead of trying to match
161+
// them up with a location.
162+
let fulfillcx = traits::FulfillmentContext::new_ignoring_regions();
163+
match traits::fully_normalize_with_fulfillcx(
164+
self.infcx, fulfillcx, cause, self.param_env, &ty
165+
) {
159166
Ok(ty) => match ty.sty {
160167
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
161168
self.add_regular_live_constraint(ty, location);

src/test/run-pass/issue-46069.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::iter::{Fuse, Cloned};
12+
use std::slice::Iter;
13+
14+
struct Foo<'a, T: 'a>(&'a T);
15+
impl<'a, T: 'a> Copy for Foo<'a, T> {}
16+
impl<'a, T: 'a> Clone for Foo<'a, T> {
17+
fn clone(&self) -> Self { *self }
18+
}
19+
20+
fn copy_ex() {
21+
let s = 2;
22+
let k1 = || s;
23+
let upvar = Foo(&k1);
24+
let k = || upvar;
25+
k();
26+
}
27+
28+
fn main() {
29+
let _f = 0 as *mut <Fuse<Cloned<Iter<u8>>> as Iterator>::Item;
30+
31+
copy_ex();
32+
}

0 commit comments

Comments
 (0)