Skip to content

Commit 99a508b

Browse files
committed
Check that predicates hold before emitting an entry for the vtable.
Fixes #23435.
1 parent 88b65c9 commit 99a508b

File tree

5 files changed

+100
-16
lines changed

5 files changed

+100
-16
lines changed

src/librustc/util/ppaux.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1053,10 +1053,11 @@ impl<'tcx> Repr<'tcx> for ty::Variance {
10531053

10541054
impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
10551055
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
1056-
format!("method(name: {}, generics: {}, fty: {}, \
1056+
format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \
10571057
explicit_self: {}, vis: {}, def_id: {})",
10581058
self.name.repr(tcx),
10591059
self.generics.repr(tcx),
1060+
self.predicates.repr(tcx),
10601061
self.fty.repr(tcx),
10611062
self.explicit_self.repr(tcx),
10621063
self.vis.repr(tcx),

src/librustc_trans/trans/common.rs

+53-14
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use arena::TypedArena;
4646
use libc::{c_uint, c_char};
4747
use std::ffi::CString;
4848
use std::cell::{Cell, RefCell};
49+
use std::result::Result as StdResult;
4950
use std::vec::Vec;
5051
use syntax::ast::Ident;
5152
use syntax::ast;
@@ -1006,9 +1007,9 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &ast::Expr) ->
10061007
/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
10071008
/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
10081009
pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1009-
span: Span,
1010-
trait_ref: ty::PolyTraitRef<'tcx>)
1011-
-> traits::Vtable<'tcx, ()>
1010+
span: Span,
1011+
trait_ref: ty::PolyTraitRef<'tcx>)
1012+
-> traits::Vtable<'tcx, ()>
10121013
{
10131014
let tcx = ccx.tcx();
10141015

@@ -1067,7 +1068,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10671068
let vtable = selection.map_move_nested(|predicate| {
10681069
fulfill_cx.register_predicate_obligation(&infcx, predicate);
10691070
});
1070-
let vtable = drain_fulfillment_cx(span, &infcx, &mut fulfill_cx, &vtable);
1071+
let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable);
10711072

10721073
info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
10731074
ccx.trait_cache().borrow_mut().insert(trait_ref,
@@ -1076,6 +1077,22 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
10761077
vtable
10771078
}
10781079

1080+
pub fn predicates_hold<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
1081+
predicates: Vec<ty::Predicate<'tcx>>)
1082+
-> bool
1083+
{
1084+
debug!("predicates_hold(predicates={})",
1085+
predicates.repr(ccx.tcx()));
1086+
1087+
let infcx = infer::new_infer_ctxt(ccx.tcx());
1088+
let mut fulfill_cx = traits::FulfillmentContext::new();
1089+
for predicate in predicates {
1090+
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), predicate);
1091+
fulfill_cx.register_predicate_obligation(&infcx, obligation);
1092+
}
1093+
drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &()).is_ok()
1094+
}
1095+
10791096
pub struct NormalizingClosureTyper<'a,'tcx:'a> {
10801097
param_env: ty::ParameterEnvironment<'a, 'tcx>
10811098
}
@@ -1123,11 +1140,36 @@ impl<'a,'tcx> ty::ClosureTyper<'tcx> for NormalizingClosureTyper<'a,'tcx> {
11231140
}
11241141
}
11251142

1143+
pub fn drain_fulfillment_cx_or_panic<'a,'tcx,T>(span: Span,
1144+
infcx: &infer::InferCtxt<'a,'tcx>,
1145+
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1146+
result: &T)
1147+
-> T
1148+
where T : TypeFoldable<'tcx> + Repr<'tcx>
1149+
{
1150+
match drain_fulfillment_cx(span, infcx, fulfill_cx, result) {
1151+
Ok(v) => v,
1152+
Err(errors) => {
1153+
infcx.tcx.sess.span_bug(
1154+
span,
1155+
&format!("Encountered errors `{}` fulfilling during trans",
1156+
errors.repr(infcx.tcx)));
1157+
}
1158+
}
1159+
}
1160+
1161+
/// Finishes processes any obligations that remain in the fulfillment
1162+
/// context, and then "freshens" and returns `result`. This is
1163+
/// primarily used during normalization and other cases where
1164+
/// processing the obligations in `fulfill_cx` may cause type
1165+
/// inference variables that appear in `result` to be unified, and
1166+
/// hence we need to process those obligations to get the complete
1167+
/// picture of the type.
11261168
pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
1127-
infcx: &infer::InferCtxt<'a,'tcx>,
1128-
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1129-
result: &T)
1130-
-> T
1169+
infcx: &infer::InferCtxt<'a,'tcx>,
1170+
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
1171+
result: &T)
1172+
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
11311173
where T : TypeFoldable<'tcx> + Repr<'tcx>
11321174
{
11331175
debug!("drain_fulfillment_cx(result={})",
@@ -1140,16 +1182,13 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
11401182
match fulfill_cx.select_all_or_error(infcx, &typer) {
11411183
Ok(()) => { }
11421184
Err(errors) => {
1185+
// We always want to surface any overflow errors, no matter what.
11431186
if errors.iter().all(|e| e.is_overflow()) {
1144-
// See Ok(None) case above.
11451187
infcx.tcx.sess.span_fatal(
11461188
span,
11471189
"reached the recursion limit during monomorphization");
11481190
} else {
1149-
infcx.tcx.sess.span_bug(
1150-
span,
1151-
&format!("Encountered errors `{}` fulfilling during trans",
1152-
errors.repr(infcx.tcx)));
1191+
return Err(errors);
11531192
}
11541193
}
11551194
}
@@ -1159,7 +1198,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(span: Span,
11591198
// sort of overkill because we do not expect there to be any
11601199
// unbound type variables, hence no `TyFresh` types should ever be
11611200
// inserted.
1162-
result.fold_with(&mut infcx.freshener())
1201+
Ok(result.fold_with(&mut infcx.freshener()))
11631202
}
11641203

11651204
// Key used to lookup values supplied for type parameters in an expr.

src/librustc_trans/trans/meth.rs

+9
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,15 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
842842
return nullptr;
843843
}
844844

845+
let predicates =
846+
monomorphize::apply_param_substs(tcx,
847+
&substs,
848+
&impl_method_type.predicates.predicates);
849+
if !predicates_hold(ccx, predicates.into_vec()) {
850+
debug!("emit_vtable_methods: predicates do not hold");
851+
return nullptr;
852+
}
853+
845854
trans_fn_ref_with_substs(ccx,
846855
impl_method_def_id,
847856
ExprId(0),

src/librustc_trans/trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
339339
for obligation in obligations {
340340
fulfill_cx.register_predicate_obligation(&infcx, obligation);
341341
}
342-
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
342+
let result = drain_fulfillment_cx_or_panic(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
343343

344344
result
345345
}

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

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2015 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+
// Test that we do not ICE when a default method implementation has
12+
// requirements (in this case, `Self : Baz`) that do not hold for some
13+
// specific impl (in this case, `Foo : Bar`). This causes problems
14+
// only when building a vtable, because that goes along and
15+
// instantiates all the methods, even those that could not otherwise
16+
// be called.
17+
18+
struct Foo {
19+
x: i32
20+
}
21+
22+
trait Bar {
23+
fn bar(&self) where Self : Baz { self.baz(); }
24+
}
25+
26+
trait Baz {
27+
fn baz(&self);
28+
}
29+
30+
impl Bar for Foo {
31+
}
32+
33+
fn main() {
34+
let x: &Bar = &Foo { x: 22 };
35+
}

0 commit comments

Comments
 (0)