Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Emit an error rather than ICEing for a missing built-in bound lang item.
closes #17392
  • Loading branch information
nrc committed Sep 29, 2014
1 parent 1f3cda8 commit 1c36d1c
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 45 deletions.
6 changes: 5 additions & 1 deletion src/librustc/middle/traits/mod.rs
Expand Up @@ -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>;
Expand Down Expand Up @@ -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)
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/middle/traits/select.rs
Expand Up @@ -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)
}

Expand Down
43 changes: 25 additions & 18 deletions src/librustc/middle/traits/util.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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() {
Expand All @@ -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
}
}
}
Expand All @@ -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)
}
}

Expand Down
15 changes: 9 additions & 6 deletions src/librustc/middle/typeck/check/mod.rs
Expand Up @@ -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,
Expand Down
8 changes: 7 additions & 1 deletion src/librustc/middle/typeck/check/regionck.rs
Expand Up @@ -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),
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/middle/typeck/check/vtable2.rs
Expand Up @@ -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
Expand Down
40 changes: 24 additions & 16 deletions src/librustc/middle/typeck/check/wf.rs
Expand Up @@ -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),
_ => {}
}
}
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 \
Expand Down
21 changes: 21 additions & 0 deletions src/test/compile-fail/lang-item-missing.rs
@@ -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
}

5 comments on commit 1c36d1c

@bors
Copy link
Contributor

@bors bors commented on 1c36d1c Sep 29, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from nikomatsakis
at nrc@1c36d1c

@bors
Copy link
Contributor

@bors bors commented on 1c36d1c Sep 29, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging nick29581/rust/dst-bug-nostd = 1c36d1c into auto

@bors
Copy link
Contributor

@bors bors commented on 1c36d1c Sep 29, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nick29581/rust/dst-bug-nostd = 1c36d1c merged ok, testing candidate = 7409050

@bors
Copy link
Contributor

@bors bors commented on 1c36d1c Sep 30, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors
Copy link
Contributor

@bors bors commented on 1c36d1c Sep 30, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 7409050

Please sign in to comment.