about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-09-23 17:18:54 +1200
committerNick Cameron <ncameron@mozilla.com>2014-09-30 11:30:08 +1300
commit1c36d1c71d0095d822ab03e7615fffc63fb16988 (patch)
treeac025061fc91cf163aee71cb4a2cd86d994daba6
parent1f3cda8bd8496c3b3771b0201d1073ed575321d0 (diff)
downloadrust-1c36d1c71d0095d822ab03e7615fffc63fb16988.tar.gz
rust-1c36d1c71d0095d822ab03e7615fffc63fb16988.zip
Emit an error rather than ICEing for a missing built-in bound lang item.
closes #17392
-rw-r--r--src/librustc/middle/traits/mod.rs6
-rw-r--r--src/librustc/middle/traits/select.rs5
-rw-r--r--src/librustc/middle/traits/util.rs43
-rw-r--r--src/librustc/middle/typeck/check/mod.rs15
-rw-r--r--src/librustc/middle/typeck/check/regionck.rs8
-rw-r--r--src/librustc/middle/typeck/check/vtable2.rs9
-rw-r--r--src/librustc/middle/typeck/check/wf.rs40
-rw-r--r--src/test/compile-fail/lang-item-missing.rs21
8 files changed, 102 insertions, 45 deletions
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index 9d66108cfc9..88685101b31 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -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)
 }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 63fbeb797c4..61477fdeed5 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -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)
     }
 
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index cad86003ce9..ab5bbf4363f 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -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)
     }
 }
 
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index d4c38d48a8c..0bf22d97345 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -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,
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index d45155c2ccd..b853616991f 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -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),
diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs
index bcbcebc3f59..bdcf4d73c3b 100644
--- a/src/librustc/middle/typeck/check/vtable2.rs
+++ b/src/librustc/middle/typeck/check/vtable2.rs
@@ -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
diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs
index 67f93feae41..587aa072fa8 100644
--- a/src/librustc/middle/typeck/check/wf.rs
+++ b/src/librustc/middle/typeck/check/wf.rs
@@ -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 \
diff --git a/src/test/compile-fail/lang-item-missing.rs b/src/test/compile-fail/lang-item-missing.rs
new file mode 100644
index 00000000000..bcde10a0b22
--- /dev/null
+++ b/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
+}