Emit an error rather than ICEing for a missing built-in bound lang item.

closes #17392
This commit is contained in:
Nick Cameron 2014-09-23 17:18:54 +12:00
parent 1f3cda8bd8
commit 1c36d1c71d
8 changed files with 102 additions and 45 deletions

View File

@ -86,6 +86,10 @@ pub enum ObligationCauseCode {
FieldSized,
}
// An error has already been reported to the user, so no need to continue checking.
#[deriving(Clone,Show)]
pub struct ErrorReported;
pub type Obligations = subst::VecPerParamSpace<Obligation>;
pub type Selection = Vtable<Obligation>;
@ -332,7 +336,7 @@ pub fn obligation_for_builtin_bound(tcx: &ty::ctxt,
cause: ObligationCause,
source_ty: ty::t,
builtin_bound: ty::BuiltinBound)
-> Obligation
-> Result<Obligation, ErrorReported>
{
util::obligation_for_builtin_bound(tcx, cause, builtin_bound, 0, source_ty)
}

View File

@ -228,6 +228,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
bound,
previous_stack.obligation.recursion_depth + 1,
ty);
let obligation = match obligation {
Ok(ob) => ob,
_ => return EvaluatedToMatch
};
self.evaluate_obligation_recursively(previous_stack, &obligation)
}

View File

@ -20,7 +20,8 @@ use syntax::ast;
use syntax::codemap::Span;
use util::ppaux::Repr;
use super::{Obligation, ObligationCause, VtableImpl, VtableParam, VtableParamData, VtableImplData};
use super::{ErrorReported, Obligation, ObligationCause, VtableImpl,
VtableParam, VtableParamData, VtableImplData};
///////////////////////////////////////////////////////////////////////////
// Supertrait iterator
@ -82,7 +83,7 @@ impl<'cx, 'tcx> Supertraits<'cx, 'tcx> {
let bound_trait_ref = trait_ref_for_builtin_bound(self.tcx,
builtin_bound,
trait_ref.self_ty());
trait_bounds.push(bound_trait_ref);
bound_trait_ref.map(|trait_ref| trait_bounds.push(trait_ref));
}
// Only keep those bounds that we haven't already seen. This
@ -213,13 +214,15 @@ fn push_obligations_for_param_bounds(
let param_ty = *param_substs.types.get(space, index);
for builtin_bound in param_bounds.builtin_bounds.iter() {
obligations.push(
space,
obligation_for_builtin_bound(tcx,
cause,
builtin_bound,
recursion_depth,
param_ty));
let obligation = obligation_for_builtin_bound(tcx,
cause,
builtin_bound,
recursion_depth,
param_ty);
match obligation {
Ok(ob) => obligations.push(space, ob),
_ => {}
}
}
for bound_trait_ref in param_bounds.trait_bounds.iter() {
@ -236,17 +239,18 @@ pub fn trait_ref_for_builtin_bound(
tcx: &ty::ctxt,
builtin_bound: ty::BuiltinBound,
param_ty: ty::t)
-> Rc<ty::TraitRef>
-> Option<Rc<ty::TraitRef>>
{
match tcx.lang_items.from_builtin_kind(builtin_bound) {
Ok(def_id) => {
Rc::new(ty::TraitRef {
Some(Rc::new(ty::TraitRef {
def_id: def_id,
substs: Substs::empty().with_self_ty(param_ty)
})
}))
}
Err(e) => {
tcx.sess.bug(e.as_slice());
tcx.sess.err(e.as_slice());
None
}
}
}
@ -257,13 +261,16 @@ pub fn obligation_for_builtin_bound(
builtin_bound: ty::BuiltinBound,
recursion_depth: uint,
param_ty: ty::t)
-> Obligation
-> Result<Obligation, ErrorReported>
{
let trait_ref = trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty);
Obligation {
cause: cause,
recursion_depth: recursion_depth,
trait_ref: trait_ref
match trait_ref {
Some(trait_ref) => Ok(Obligation {
cause: cause,
recursion_depth: recursion_depth,
trait_ref: trait_ref
}),
None => Err(ErrorReported)
}
}

View File

@ -1795,12 +1795,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
code: traits::ObligationCauseCode,
bound: ty::BuiltinBound)
{
self.register_obligation(
traits::obligation_for_builtin_bound(
self.tcx(),
traits::ObligationCause::new(span, code),
ty,
bound));
let obligation = traits::obligation_for_builtin_bound(
self.tcx(),
traits::ObligationCause::new(span, code),
ty,
bound);
match obligation {
Ok(ob) => self.register_obligation(ob),
_ => {}
}
}
pub fn require_type_is_sized(&self,

View File

@ -945,7 +945,13 @@ fn check_expr_fn_block(rcx: &mut Rcx,
let cause = traits::ObligationCause::new(freevar.span, code);
let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause,
var_ty, builtin_bound);
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(), obligation);
match obligation {
Ok(obligation) => {
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(),
obligation)
}
_ => {}
}
}
type_must_outlive(
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),

View File

@ -170,13 +170,16 @@ pub fn register_object_cast_obligations(fcx: &FnCtxt,
// object type is Foo+Send, this would create an obligation
// for the Send check.)
for builtin_bound in object_trait.bounds.builtin_bounds.iter() {
fcx.register_obligation(
obligation_for_builtin_bound(
let obligation = obligation_for_builtin_bound(
fcx.tcx(),
ObligationCause::new(span,
traits::ObjectCastObligation(object_trait_ty)),
referent_ty,
builtin_bound));
builtin_bound);
match obligation {
Ok(obligation) => fcx.register_obligation(obligation),
_ => {}
}
}
object_trait_ref

View File

@ -124,11 +124,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
if variant.fields.len() > 0 {
for field in variant.fields.init().iter() {
let cause = traits::ObligationCause::new(field.span, traits::FieldSized);
fcx.register_obligation(
traits::obligation_for_builtin_bound(fcx.tcx(),
cause,
field.ty,
ty::BoundSized));
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
cause,
field.ty,
ty::BoundSized);
match obligation {
Ok(obligation) => fcx.register_obligation(obligation),
_ => {}
}
}
}
}
@ -213,11 +216,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
&trait_def.bounds,
trait_ref.self_ty());
for builtin_bound in trait_def.bounds.builtin_bounds.iter() {
fcx.register_obligation(
traits::obligation_for_builtin_bound(fcx.tcx(),
cause,
trait_ref.self_ty(),
builtin_bound));
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
cause,
trait_ref.self_ty(),
builtin_bound);
match obligation {
Ok (obligation) => fcx.register_obligation(obligation),
_ => {}
}
}
for trait_bound in trait_def.bounds.trait_bounds.iter() {
let trait_bound = trait_bound.subst(fcx.tcx(), &trait_ref.substs);
@ -453,12 +459,14 @@ fn check_struct_safe_for_destructor(fcx: &FnCtxt,
&& !struct_tpt.generics.has_region_params(subst::TypeSpace)
{
let cause = traits::ObligationCause::new(span, traits::DropTrait);
fcx.register_obligation(
traits::obligation_for_builtin_bound(
fcx.tcx(),
cause,
self_ty,
ty::BoundSend));
let obligation = traits::obligation_for_builtin_bound(fcx.tcx(),
cause,
self_ty,
ty::BoundSend);
match obligation {
Ok(obligation) => fcx.register_obligation(obligation),
_ => {}
}
} else {
span_err!(fcx.tcx().sess, span, E0141,
"cannot implement a destructor on a structure \

View File

@ -0,0 +1,21 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that a missing lang item (in this case `sized`) does not cause an ICE,
// see #17392.
// error-pattern: requires `sized` lang_item
#![no_std]
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
0
}