about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-01-31 13:06:39 -0800
committerbors <bors@rust-lang.org>2014-01-31 13:06:39 -0800
commit5a618129b842f875dac5531ce7b8385fe4fcda6c (patch)
treef5e2224945382f98a42856b485c3b42b0fd227a7
parentf47879637f464b124875889c9a4822099c777cfb (diff)
parent9b1865a7faafe16af9eb9f804e82065b5a6f1e24 (diff)
downloadrust-5a618129b842f875dac5531ce7b8385fe4fcda6c.tar.gz
rust-5a618129b842f875dac5531ce7b8385fe4fcda6c.zip
auto merge of #11832 : jfager/rust/r5900, r=alexcrichton
I tried a couple of different ways to squash this, and still don't think this is ideal, but I wanted to get it out for feedback.

Closes #5900
Closes #9942

There are a few scenarios where the compiler tries to evaluate CastExprs without the corresponding types being available yet in the type context:  https://github.com/mozilla/rust/issues/10618, https://github.com/mozilla/rust/issues/5900, https://github.com/mozilla/rust/issues/9942

This PR takes the approach of having eval_const_expr_partial's CastExpr arm fall back to a limited ast_ty_to_ty call that only checks for (a subset of) valid const types, when the direct type lookup fails.  It's kind of hacky, so I understand if you don't want to take this as is.  I'd need a little mentoring to get this into better shape, as figuring out the proper fix has been a little daunting. I'm also happy if someone else wants to pick this up and run with it.

This closes 5900 and 9942, but only moves the goalposts a little on 10618, which now falls over in a later phase of the compiler.  
-rw-r--r--src/librustc/middle/const_eval.rs15
-rw-r--r--src/librustc/middle/ty.rs19
-rw-r--r--src/librustc/middle/typeck/astconv.rs425
-rw-r--r--src/librustc/middle/typeck/check/mod.rs1
-rw-r--r--src/test/run-pass/issue-5900.rs21
-rw-r--r--src/test/run-pass/issue-9942.rs13
6 files changed, 285 insertions, 209 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 770275f3f6a..59057128555 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -11,7 +11,9 @@
 
 use metadata::csearch;
 use middle::astencode;
+
 use middle::ty;
+use middle::typeck::astconv;
 use middle;
 
 use syntax::{ast, ast_map, ast_util};
@@ -445,8 +447,17 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
           _ => Err(~"Bad operands for binary")
         }
       }
-      ExprCast(base, _) => {
-        let ety = tcx.expr_ty(e);
+      ExprCast(base, target_ty) => {
+        // This tends to get called w/o the type actually having been
+        // populated in the ctxt, which was causing things to blow up
+        // (#5900). Fall back to doing a limited lookup to get past it.
+        let ety = ty::expr_ty_opt(tcx.ty_ctxt(), e)
+                .or_else(|| astconv::ast_ty_to_prim_ty(tcx.ty_ctxt(), target_ty))
+                .unwrap_or_else(|| tcx.ty_ctxt().sess.span_fatal(
+                    target_ty.span,
+                    format!("Target type not found for const cast")
+                ));
+
         let base = eval_const_expr_partial(tcx, base);
         match base {
             Err(_) => base,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 3b5dd67366c..f216a1cc0a2 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -2669,10 +2669,8 @@ pub fn node_id_to_trait_ref(cx: ctxt, id: ast::NodeId) -> @ty::TraitRef {
 }
 
 pub fn node_id_to_type(cx: ctxt, id: ast::NodeId) -> t {
-    //printfln!("{:?}/{:?}", id, cx.node_types.len());
-    let node_types = cx.node_types.borrow();
-    match node_types.get().find(&(id as uint)) {
-       Some(&t) => t,
+    match node_id_to_type_opt(cx, id) {
+       Some(t) => t,
        None => cx.sess.bug(
            format!("node_id_to_type: no type for node `{}`",
                 ast_map::node_id_to_str(cx.items, id,
@@ -2680,6 +2678,15 @@ pub fn node_id_to_type(cx: ctxt, id: ast::NodeId) -> t {
     }
 }
 
+pub fn node_id_to_type_opt(cx: ctxt, id: ast::NodeId) -> Option<t> {
+    let node_types = cx.node_types.borrow();
+    debug!("id: {:?}, node_types: {:?}", id, node_types);
+    match node_types.get().find(&(id as uint)) {
+       Some(&t) => Some(t),
+       None => None
+    }
+}
+
 // FIXME(pcwalton): Makes a copy, bleh. Probably better to not do that.
 pub fn node_id_to_type_params(cx: ctxt, id: ast::NodeId) -> ~[t] {
     let node_type_substs = cx.node_type_substs.borrow();
@@ -2850,6 +2857,10 @@ pub fn expr_ty(cx: ctxt, expr: &ast::Expr) -> t {
     return node_id_to_type(cx, expr.id);
 }
 
+pub fn expr_ty_opt(cx: ctxt, expr: &ast::Expr) -> Option<t> {
+    return node_id_to_type_opt(cx, expr.id);
+}
+
 pub fn expr_ty_adjusted(cx: ctxt, expr: &ast::Expr) -> t {
     /*!
      *
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 144ce99198f..565ff4a7345 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -299,6 +299,74 @@ pub fn ast_path_to_ty<AC:AstConv,RS:RegionScope>(
 pub static NO_REGIONS: uint = 1;
 pub static NO_TPS: uint = 2;
 
+fn check_path_args(tcx: ty::ctxt,
+                   path: &ast::Path,
+                   flags: uint) {
+    if (flags & NO_TPS) != 0u {
+        if !path.segments.iter().all(|s| s.types.is_empty()) {
+            tcx.sess.span_err(
+                path.span,
+                "type parameters are not allowed on this type");
+        }
+    }
+
+    if (flags & NO_REGIONS) != 0u {
+        if !path.segments.last().unwrap().lifetimes.is_empty() {
+            tcx.sess.span_err(
+                path.span,
+                "region parameters are not allowed on this type");
+        }
+    }
+}
+
+pub fn ast_ty_to_prim_ty(tcx: ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
+    match ast_ty.node {
+        ast::TyPath(ref path, _, id) => {
+            let def_map = tcx.def_map.borrow();
+            let a_def = match def_map.get().find(&id) {
+                None => tcx.sess.span_fatal(
+                    ast_ty.span, format!("unbound path {}",
+                                         path_to_str(path, tcx.sess.intr()))),
+                Some(&d) => d
+            };
+            match a_def {
+                ast::DefPrimTy(nty) => {
+                    match nty {
+                        ast::TyBool => {
+                            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                            Some(ty::mk_bool())
+                        }
+                        ast::TyChar => {
+                            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                            Some(ty::mk_char())
+                        }
+                        ast::TyInt(it) => {
+                            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                            Some(ty::mk_mach_int(it))
+                        }
+                        ast::TyUint(uit) => {
+                            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                            Some(ty::mk_mach_uint(uit))
+                        }
+                        ast::TyFloat(ft) => {
+                            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                            Some(ty::mk_mach_float(ft))
+                        }
+                        ast::TyStr => {
+                            tcx.sess.span_err(ast_ty.span,
+                                              "bare `str` is not a type");
+                            // return /something/ so they can at least get more errors
+                            Some(ty::mk_str(tcx, ty::vstore_uniq))
+                        }
+                    }
+                }
+                _ => None
+            }
+        }
+        _ => None
+    }
+}
+
 // Parses the programmer's textual representation of a type into our
 // internal notion of a type.
 pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
@@ -384,26 +452,6 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
         return constr(seq_ty);
     }
 
-    fn check_path_args(tcx: ty::ctxt,
-                       path: &ast::Path,
-                       flags: uint) {
-        if (flags & NO_TPS) != 0u {
-            if !path.segments.iter().all(|s| s.types.is_empty()) {
-                tcx.sess.span_err(
-                    path.span,
-                    "type parameters are not allowed on this type");
-            }
-        }
-
-        if (flags & NO_REGIONS) != 0u {
-            if !path.segments.last().unwrap().lifetimes.is_empty() {
-                tcx.sess.span_err(
-                    path.span,
-                    "region parameters are not allowed on this type");
-            }
-        }
-    }
-
     let tcx = this.tcx();
 
     {
@@ -421,191 +469,164 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
         ast_ty_to_ty_cache.get().insert(ast_ty.id, ty::atttce_unresolved);
     }
 
-
-    let typ = match ast_ty.node {
-      ast::TyNil => ty::mk_nil(),
-      ast::TyBot => ty::mk_bot(),
-      ast::TyBox(ty) => {
-        let mt = ast::MutTy { ty: ty, mutbl: ast::MutImmutable };
-        mk_pointer(this, rscope, &mt, ty::vstore_box,
-                   |tmt| ty::mk_box(tcx, tmt.ty))
-      }
-      ast::TyUniq(ty) => {
-        let mt = ast::MutTy { ty: ty, mutbl: ast::MutImmutable };
-        mk_pointer(this, rscope, &mt, ty::vstore_uniq,
-                   |tmt| ty::mk_uniq(tcx, tmt.ty))
-      }
-      ast::TyVec(ty) => {
-        tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type");
-        // return /something/ so they can at least get more errors
-        ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty), ty::vstore_uniq)
-      }
-      ast::TyPtr(ref mt) => {
-        ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt))
-      }
-      ast::TyRptr(ref region, ref mt) => {
-        let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
-        debug!("ty_rptr r={}", r.repr(this.tcx()));
-        mk_pointer(this, rscope, mt, ty::vstore_slice(r),
-                   |tmt| ty::mk_rptr(tcx, r, tmt))
-      }
-      ast::TyTup(ref fields) => {
-        let flds = fields.map(|&t| ast_ty_to_ty(this, rscope, t));
-        ty::mk_tup(tcx, flds)
-      }
-      ast::TyBareFn(ref bf) => {
-          if bf.decl.variadic && !bf.abis.is_c() {
-            tcx.sess.span_err(ast_ty.span, "variadic function must have C calling convention");
-          }
-          ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity,
-                                            bf.abis, bf.decl))
-      }
-      ast::TyClosure(ref f) => {
-        if f.sigil == ast::ManagedSigil {
-            tcx.sess.span_err(ast_ty.span,
-                              "managed closures are not supported");
-        }
-
-          let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
-              // Use corresponding trait store to figure out default bounds
-              // if none were specified.
-              ast::BorrowedSigil => ty::RegionTraitStore(ty::ReEmpty), // dummy region
-              ast::OwnedSigil    => ty::UniqTraitStore,
-              ast::ManagedSigil  => ty::BoxTraitStore,
-          });
-          let fn_decl = ty_of_closure(this,
-                                      rscope,
-                                      ast_ty.id,
-                                      f.sigil,
-                                      f.purity,
-                                      f.onceness,
-                                      bounds,
-                                      &f.region,
-                                      f.decl,
-                                      None,
-                                      ast_ty.span);
-          ty::mk_closure(tcx, fn_decl)
-      }
-      ast::TyPath(ref path, ref bounds, id) => {
-        let def_map = tcx.def_map.borrow();
-        let a_def = match def_map.get().find(&id) {
-          None => tcx.sess.span_fatal(
-              ast_ty.span, format!("unbound path {}",
-                                path_to_str(path, tcx.sess.intr()))),
-          Some(&d) => d
-        };
-        // Kind bounds on path types are only supported for traits.
-        match a_def {
-            // But don't emit the error if the user meant to do a trait anyway.
-            ast::DefTrait(..) => { },
-            _ if bounds.is_some() =>
-                tcx.sess.span_err(ast_ty.span,
-                    "kind bounds can only be used on trait types"),
-            _ => { },
-        }
-        match a_def {
-          ast::DefTrait(_) => {
-              let path_str = path_to_str(path, tcx.sess.intr());
-              tcx.sess.span_err(
-                  ast_ty.span,
-                  format!("reference to trait `{}` where a type is expected; \
-                        try `@{}`, `~{}`, or `&{}`",
-                       path_str, path_str, path_str, path_str));
-              ty::mk_err()
-          }
-          ast::DefTy(did) | ast::DefStruct(did) => {
-            ast_path_to_ty(this, rscope, did, path).ty
-          }
-          ast::DefPrimTy(nty) => {
-            match nty {
-              ast::TyBool => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                ty::mk_bool()
-              }
-              ast::TyChar => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                ty::mk_char()
-              }
-              ast::TyInt(it) => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                ty::mk_mach_int(it)
-              }
-              ast::TyUint(uit) => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                ty::mk_mach_uint(uit)
-              }
-              ast::TyFloat(ft) => {
-                check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-                ty::mk_mach_float(ft)
-              }
-              ast::TyStr => {
-                tcx.sess.span_err(ast_ty.span,
-                                  "bare `str` is not a type");
+    let typ = ast_ty_to_prim_ty(tcx, ast_ty).unwrap_or_else(|| match ast_ty.node {
+            ast::TyNil => ty::mk_nil(),
+            ast::TyBot => ty::mk_bot(),
+            ast::TyBox(ty) => {
+                let mt = ast::MutTy { ty: ty, mutbl: ast::MutImmutable };
+                mk_pointer(this, rscope, &mt, ty::vstore_box,
+                           |tmt| ty::mk_box(tcx, tmt.ty))
+            }
+            ast::TyUniq(ty) => {
+                let mt = ast::MutTy { ty: ty, mutbl: ast::MutImmutable };
+                mk_pointer(this, rscope, &mt, ty::vstore_uniq,
+                           |tmt| ty::mk_uniq(tcx, tmt.ty))
+            }
+            ast::TyVec(ty) => {
+                tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type");
                 // return /something/ so they can at least get more errors
-                ty::mk_str(tcx, ty::vstore_uniq)
-              }
+                ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty), ty::vstore_uniq)
             }
-          }
-          ast::DefTyParam(id, n) => {
-            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-            ty::mk_param(tcx, n, id)
-          }
-          ast::DefSelfTy(id) => {
-            // n.b.: resolve guarantees that the this type only appears in a
-            // trait, which we rely upon in various places when creating
-            // substs
-            check_path_args(tcx, path, NO_TPS | NO_REGIONS);
-            let did = ast_util::local_def(id);
-            ty::mk_self(tcx, did)
-          }
-          ast::DefMod(id) => {
-            tcx.sess.span_fatal(ast_ty.span,
-                                format!("found module name used as a type: {}",
-                                        ast_map::node_id_to_str(tcx.items, id.node,
-                                        token::get_ident_interner())));
-          }
-          _ => {
-            tcx.sess.span_fatal(ast_ty.span,
-                                format!("found value name used as a type: {:?}", a_def));
-          }
-        }
-      }
-      ast::TyFixedLengthVec(ty, e) => {
-        match const_eval::eval_const_expr_partial(&tcx, e) {
-          Ok(ref r) => {
-            match *r {
-              const_eval::const_int(i) =>
-                ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty),
-                           ty::vstore_fixed(i as uint)),
-              const_eval::const_uint(i) =>
-                ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty),
-                           ty::vstore_fixed(i as uint)),
-              _ => {
-                tcx.sess.span_fatal(
-                    ast_ty.span, "expected constant expr for vector length");
-              }
+            ast::TyPtr(ref mt) => {
+                ty::mk_ptr(tcx, ast_mt_to_mt(this, rscope, mt))
             }
-          }
-          Err(ref r) => {
-            tcx.sess.span_fatal(
-                ast_ty.span,
-                format!("expected constant expr for vector length: {}", *r));
-          }
-        }
-      }
-      ast::TyTypeof(_e) => {
-          tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
-      }
-      ast::TyInfer => {
-        // ty_infer should only appear as the type of arguments or return
-        // values in a fn_expr, or as the type of local variables.  Both of
-        // these cases are handled specially and should not descend into this
-        // routine.
-        this.tcx().sess.span_bug(
-            ast_ty.span,
-            "found `ty_infer` in unexpected place");
-      }
-    };
+            ast::TyRptr(ref region, ref mt) => {
+                let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
+                debug!("ty_rptr r={}", r.repr(this.tcx()));
+                mk_pointer(this, rscope, mt, ty::vstore_slice(r),
+                           |tmt| ty::mk_rptr(tcx, r, tmt))
+            }
+            ast::TyTup(ref fields) => {
+                let flds = fields.map(|&t| ast_ty_to_ty(this, rscope, t));
+                ty::mk_tup(tcx, flds)
+            }
+            ast::TyBareFn(ref bf) => {
+                if bf.decl.variadic && !bf.abis.is_c() {
+                    tcx.sess.span_err(ast_ty.span,
+                                      "variadic function must have C calling convention");
+                }
+                ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.purity,
+                                                  bf.abis, bf.decl))
+            }
+            ast::TyClosure(ref f) => {
+                if f.sigil == ast::ManagedSigil {
+                    tcx.sess.span_err(ast_ty.span,
+                                      "managed closures are not supported");
+                }
+
+                let bounds = conv_builtin_bounds(this.tcx(), &f.bounds, match f.sigil {
+                        // Use corresponding trait store to figure out default bounds
+                        // if none were specified.
+                        ast::BorrowedSigil => ty::RegionTraitStore(ty::ReEmpty), // dummy region
+                        ast::OwnedSigil    => ty::UniqTraitStore,
+                        ast::ManagedSigil  => ty::BoxTraitStore,
+                    });
+                let fn_decl = ty_of_closure(this,
+                                            rscope,
+                                            ast_ty.id,
+                                            f.sigil,
+                                            f.purity,
+                                            f.onceness,
+                                            bounds,
+                                            &f.region,
+                                            f.decl,
+                                            None,
+                                            ast_ty.span);
+                ty::mk_closure(tcx, fn_decl)
+            }
+            ast::TyPath(ref path, ref bounds, id) => {
+                let def_map = tcx.def_map.borrow();
+                let a_def = match def_map.get().find(&id) {
+                    None => tcx.sess.span_fatal(
+                        ast_ty.span, format!("unbound path {}",
+                                             path_to_str(path, tcx.sess.intr()))),
+                    Some(&d) => d
+                };
+                // Kind bounds on path types are only supported for traits.
+                match a_def {
+                    // But don't emit the error if the user meant to do a trait anyway.
+                    ast::DefTrait(..) => { },
+                    _ if bounds.is_some() =>
+                        tcx.sess.span_err(ast_ty.span,
+                                          "kind bounds can only be used on trait types"),
+                    _ => { },
+                }
+                match a_def {
+                    ast::DefTrait(_) => {
+                        let path_str = path_to_str(path, tcx.sess.intr());
+                        tcx.sess.span_err(
+                            ast_ty.span,
+                            format!("reference to trait `{}` where a type is expected; \
+                                    try `@{}`, `~{}`, or `&{}`",
+                                    path_str, path_str, path_str, path_str));
+                        ty::mk_err()
+                    }
+                    ast::DefTy(did) | ast::DefStruct(did) => {
+                        ast_path_to_ty(this, rscope, did, path).ty
+                    }
+                    ast::DefTyParam(id, n) => {
+                        check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                        ty::mk_param(tcx, n, id)
+                    }
+                    ast::DefSelfTy(id) => {
+                        // n.b.: resolve guarantees that the this type only appears in a
+                        // trait, which we rely upon in various places when creating
+                        // substs
+                        check_path_args(tcx, path, NO_TPS | NO_REGIONS);
+                        let did = ast_util::local_def(id);
+                        ty::mk_self(tcx, did)
+                    }
+                    ast::DefMod(id) => {
+                        tcx.sess.span_fatal(ast_ty.span,
+                            format!("found module name used as a type: {}",
+                                    ast_map::node_id_to_str(tcx.items, id.node,
+                                                            token::get_ident_interner())));
+                    }
+                    ast::DefPrimTy(_) => {
+                        fail!("DefPrimTy arm missed in previous ast_ty_to_prim_ty call");
+                    }
+                    _ => {
+                        tcx.sess.span_fatal(ast_ty.span,
+                            format!("found value name used as a type: {:?}", a_def));
+                    }
+                }
+            }
+            ast::TyFixedLengthVec(ty, e) => {
+                match const_eval::eval_const_expr_partial(&tcx, e) {
+                    Ok(ref r) => {
+                        match *r {
+                            const_eval::const_int(i) =>
+                                ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty),
+                                           ty::vstore_fixed(i as uint)),
+                            const_eval::const_uint(i) =>
+                                ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, ty),
+                                           ty::vstore_fixed(i as uint)),
+                            _ => {
+                                tcx.sess.span_fatal(
+                                    ast_ty.span, "expected constant expr for vector length");
+                            }
+                        }
+                    }
+                    Err(ref r) => {
+                        tcx.sess.span_fatal(
+                            ast_ty.span,
+                            format!("expected constant expr for vector length: {}", *r));
+                    }
+                }
+            }
+            ast::TyTypeof(_e) => {
+                tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+            }
+            ast::TyInfer => {
+                // ty_infer should only appear as the type of arguments or return
+                // values in a fn_expr, or as the type of local variables.  Both of
+                // these cases are handled specially and should not descend into this
+                // routine.
+                this.tcx().sess.span_bug(
+                    ast_ty.span,
+                    "found `ty_infer` in unexpected place");
+            }
+        });
 
     let mut ast_ty_to_ty_cache = tcx.ast_ty_to_ty_cache.borrow_mut();
     ast_ty_to_ty_cache.get().insert(ast_ty.id, ty::atttce_resolved(typ));
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 5e6e3c95692..31dc0063ad6 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -4314,4 +4314,3 @@ pub fn check_intrinsic_type(ccx: @CrateCtxt, it: &ast::ForeignItem) {
                      ppaux::ty_to_str(ccx.tcx, fty)));
     }
 }
-
diff --git a/src/test/run-pass/issue-5900.rs b/src/test/run-pass/issue-5900.rs
new file mode 100644
index 00000000000..4518b503c0d
--- /dev/null
+++ b/src/test/run-pass/issue-5900.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.
+
+pub mod foo {
+    use super::Bar;
+
+    pub struct FooStruct { bar : Bar }
+}
+
+pub enum Bar {
+    Bar0 = 0 as int
+}
+
+pub fn main() {}
diff --git a/src/test/run-pass/issue-9942.rs b/src/test/run-pass/issue-9942.rs
new file mode 100644
index 00000000000..7864f4fbdd6
--- /dev/null
+++ b/src/test/run-pass/issue-9942.rs
@@ -0,0 +1,13 @@
+// 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.
+
+pub fn main() {
+    static S: uint = 23 as uint; [0, ..S]; ()
+}