]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15076 : luqmana/rust/naim, r=pcwalton
authorbors <bors@rust-lang.org>
Thu, 3 Jul 2014 19:56:47 +0000 (19:56 +0000)
committerbors <bors@rust-lang.org>
Thu, 3 Jul 2014 19:56:47 +0000 (19:56 +0000)
```Rust
struct With {
    x: int,
    f: NoCopy
}

#[no_mangle]
fn bar() {
    let mine = With { x: 3, f: NoCopy };
    match mine {
        c => {
            foo(c);
        }
    }
}

#[no_mangle]
fn foo(_: With) {}
```

Before:
```LLVM
define internal void @bar() unnamed_addr #1 {
entry-block:
  %mine = alloca %"struct.With<[]>"
  %__llmatch = alloca %"struct.With<[]>"*
  %c = alloca %"struct.With<[]>"
  %0 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 0
  store i64 3, i64* %0
  %1 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 1
  store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %__llmatch
  br label %case_body

case_body:                                        ; preds = %entry-block
  %2 = load %"struct.With<[]>"** %__llmatch
  %3 = bitcast %"struct.With<[]>"* %2 to i8*
  %4 = bitcast %"struct.With<[]>"* %c to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %3, i64 8, i32 8, i1 false)
  %5 = load %"struct.With<[]>"* %c
  call void @foo(%"struct.With<[]>" %5)
  br label %join

join:                                             ; preds = %case_body
  ret void
}
```

After:
```LLVM
define internal void @bar() unnamed_addr #1 {
entry-block:
  %mine = alloca %"struct.With<[]>"
  %c = alloca %"struct.With<[]>"*
  %0 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 0
  store i64 3, i64* %0
  %1 = getelementptr inbounds %"struct.With<[]>"* %mine, i32 0, i32 1
  store %"struct.With<[]>"* %mine, %"struct.With<[]>"** %c
  br label %case_body

case_body:                                        ; preds = %entry-block
  %2 = load %"struct.With<[]>"** %c
  %3 = load %"struct.With<[]>"* %2
  call void @foo(%"struct.With<[]>" %3)
  br label %join

join:                                             ; preds = %case_body
  ret void
}
```

r? @pcwalton

13 files changed:
src/doc/rust.md
src/doc/rustdoc.md
src/etc/install.sh
src/libcore/num/mod.rs
src/libcoretest/num/int_macros.rs
src/libcoretest/num/uint_macros.rs
src/libnum/rational.rs
src/librustc/middle/check_match.rs
src/librustc/middle/lang_items.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/callee.rs
src/librustc/middle/trans/debuginfo.rs
src/test/debuginfo/type-names.rs [new file with mode: 0644]

index 58819a3cf48ee2454d9958f85cc7aac28ebb7af1..11e635a5af69737062021686b9a4234b055dbb9f 100644 (file)
@@ -2155,8 +2155,6 @@ These are functions:
 
 * `str_eq`
   : Compare two strings (`&str`) for equality.
-* `uniq_str_eq`
-  : Compare two owned strings (`String`) for equality.
 * `strdup_uniq`
   : Return a new unique string
     containing a copy of the contents of a unique string.
index 8199eaea82c683b7cc29489b682e11fa8d9d89db..07a93e58456b94a680378e960193788db994c7b7 100644 (file)
@@ -51,7 +51,7 @@ Calculates the factorial of a number.
 
 Given the input integer `n`, this function will calculate `n!` and return it.
 "]
-pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} }
+pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n - 1)} }
 # fn main() {}
 ~~~
 
index dc09c7dfd00da7d3e787904162a7aea07f31c7a0..fd4c20d73c5d1df40979ed95a3f691026caed0b3 100644 (file)
@@ -35,6 +35,13 @@ need_ok() {
     fi
 }
 
+need_cmd() {
+    if command -v $1 >/dev/null 2>&1
+    then msg "found $1"
+    else err "need $1"
+    fi
+}
+
 putvar() {
     local T
     eval T=\$$1
@@ -198,6 +205,15 @@ absolutify() {
     ABSOLUTIFIED="${FILE_PATH}"
 }
 
+msg "looking for install programs"
+need_cmd mkdir
+need_cmd printf
+need_cmd cut
+need_cmd grep
+need_cmd uname
+need_cmd tr
+need_cmd sed
+
 CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
 CFG_SELF="$0"
 CFG_ARGS="$@"
@@ -216,16 +232,65 @@ else
     step_msg "processing $CFG_SELF args"
 fi
 
+# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE.
+# This logic is duplicated from configure in order to get the correct libdir
+# for Windows installs.
+CFG_OSTYPE=$(uname -s)
+
+case $CFG_OSTYPE in
+
+    MINGW32*)
+        CFG_OSTYPE=pc-mingw32
+        ;;
+
+    MINGW64*)
+        # msys2, MSYSTEM=MINGW64
+        CFG_OSTYPE=w64-mingw32
+        ;;
+
+# Thad's Cygwin identifers below
+
+#   Vista 32 bit
+    CYGWIN_NT-6.0)
+        CFG_OSTYPE=pc-mingw32
+        ;;
+
+#   Vista 64 bit
+    CYGWIN_NT-6.0-WOW64)
+        CFG_OSTYPE=w64-mingw32
+        ;;
+
+#   Win 7 32 bit
+    CYGWIN_NT-6.1)
+        CFG_OSTYPE=pc-mingw32
+        ;;
+
+#   Win 7 64 bit
+    CYGWIN_NT-6.1-WOW64)
+        CFG_OSTYPE=w64-mingw32
+        ;;
+esac
+
 OPTIONS=""
 BOOL_OPTIONS=""
 VAL_OPTIONS=""
 
+# On windows we just store the libraries in the bin directory because
+# there's no rpath. This is where the build system itself puts libraries;
+# --libdir is used to configure the installation directory.
+# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk
+CFG_LIBDIR_RELATIVE=lib
+if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
+then
+    CFG_LIBDIR_RELATIVE=bin
+fi
+
 flag uninstall "only uninstall from the installation prefix"
 opt verify 1 "verify that the installed binaries run correctly"
 valopt prefix "/usr/local" "set installation prefix"
 # NB This isn't quite the same definition as in `configure`.
 # just using 'lib' instead of CFG_LIBDIR_RELATIVE
-valopt libdir "${CFG_PREFIX}/lib" "install libraries"
+valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries"
 valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
 
 if [ $HELP -eq 1 ]
@@ -384,7 +449,7 @@ while read p; do
     need_ok "failed to update manifest"
 
 # The manifest lists all files to install
-done < "${CFG_SRC_DIR}/lib/rustlib/manifest.in"
+done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in"
 
 # Sanity check: can we run the installed binaries?
 if [ -z "${CFG_DISABLE_VERIFY}" ]
index b32e4167da1d45e90517b74a4e36b0a55af6791b..1fae362471d9c8f168c77160af8182a871fac88b 100644 (file)
@@ -586,14 +586,14 @@ fn trailing_zeros(self) -> $T { unsafe { $cttz(self) } }
             fn rotate_left(self, n: uint) -> $T {
                 // Protect against undefined behaviour for over-long bit shifts
                 let n = n % $BITS;
-                (self << n) | (self >> ($BITS - n))
+                (self << n) | (self >> (($BITS - n) % $BITS))
             }
 
             #[inline]
             fn rotate_right(self, n: uint) -> $T {
                 // Protect against undefined behaviour for over-long bit shifts
                 let n = n % $BITS;
-                (self >> n) | (self << ($BITS - n))
+                (self >> n) | (self << (($BITS - n) % $BITS))
             }
 
             #[inline]
index 940b036ca907be036b4a7003ba70186d79c66738..d078b51408512fa5e0d13b572a4da0bee79b4c00 100644 (file)
@@ -114,6 +114,15 @@ fn test_rotate() {
         assert_eq!(_1.rotate_left(124), _1);
         assert_eq!(_0.rotate_right(124), _0);
         assert_eq!(_1.rotate_right(124), _1);
+
+        // Rotating by 0 should have no effect
+        assert_eq!(A.rotate_left(0), A);
+        assert_eq!(B.rotate_left(0), B);
+        assert_eq!(C.rotate_left(0), C);
+        // Rotating by a multiple of word size should also have no effect
+        assert_eq!(A.rotate_left(64), A);
+        assert_eq!(B.rotate_left(64), B);
+        assert_eq!(C.rotate_left(64), C);
     }
 
     #[test]
index 2272af67daf8580b7303aeb1f84d4a341ba70a5a..aefaa90520e798a339d35ef7d15adfad12c0f8ff 100644 (file)
@@ -74,6 +74,15 @@ fn test_rotate() {
         assert_eq!(_1.rotate_left(124), _1);
         assert_eq!(_0.rotate_right(124), _0);
         assert_eq!(_1.rotate_right(124), _1);
+
+        // Rotating by 0 should have no effect
+        assert_eq!(A.rotate_left(0), A);
+        assert_eq!(B.rotate_left(0), B);
+        assert_eq!(C.rotate_left(0), C);
+        // Rotating by a multiple of word size should also have no effect
+        assert_eq!(A.rotate_left(64), A);
+        assert_eq!(B.rotate_left(64), B);
+        assert_eq!(C.rotate_left(64), C);
     }
 
     #[test]
index 9a455edf2c086e8d034b5c178847fda15b556ae5..c35b2976b407f19aef7f9614c48d2f3fc19e4bd7 100644 (file)
@@ -274,12 +274,17 @@ impl<T: Clone + Integer + PartialOrd>
     Num for Ratio<T> {}
 
 /* String conversions */
-impl<T: fmt::Show> fmt::Show for Ratio<T> {
-    /// Renders as `numer/denom`.
+impl<T: fmt::Show + Eq + One> fmt::Show for Ratio<T> {
+    /// Renders as `numer/denom`. If denom=1, renders as numer.
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}/{}", self.numer, self.denom)
+        if self.denom == One::one() {
+            write!(f, "{}", self.numer)
+        } else {
+            write!(f, "{}/{}", self.numer, self.denom)
+        }
     }
 }
+
 impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
     /// Renders as `numer/denom` where the numbers are in base `radix`.
     fn to_str_radix(&self, radix: uint) -> String {
@@ -291,21 +296,20 @@ fn to_str_radix(&self, radix: uint) -> String {
 
 impl<T: FromStr + Clone + Integer + PartialOrd>
     FromStr for Ratio<T> {
-    /// Parses `numer/denom`.
+    /// Parses `numer/denom` or just `numer`
     fn from_str(s: &str) -> Option<Ratio<T>> {
-        let split: Vec<&str> = s.splitn('/', 1).collect();
-        if split.len() < 2 {
-            return None
+        let mut split = s.splitn('/', 1);
+
+        let num = split.next().and_then(|n| FromStr::from_str(n));
+        let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d));
+
+        match (num, den) {
+            (Some(n), Some(d)) => Some(Ratio::new(n, d)),
+            _ => None
         }
-        let a_option: Option<T> = FromStr::from_str(*split.get(0));
-        a_option.and_then(|a| {
-            let b_option: Option<T> = FromStr::from_str(*split.get(1));
-            b_option.and_then(|b| {
-                Some(Ratio::new(a.clone(), b.clone()))
-            })
-        })
     }
 }
+
 impl<T: FromStrRadix + Clone + Integer + PartialOrd>
     FromStrRadix for Ratio<T> {
     /// Parses `numer/denom` where the numbers are in base `radix`.
@@ -429,6 +433,13 @@ fn test_is_integer() {
         assert!(!_neg1_2.is_integer());
     }
 
+    #[test]
+    fn test_show() {
+        assert_eq!(format!("{}", _2), "2".to_string());
+        assert_eq!(format!("{}", _1_2), "1/2".to_string());
+        assert_eq!(format!("{}", _0), "0".to_string());
+        assert_eq!(format!("{}", Ratio::from_integer(-2i)), "-2".to_string());
+    }
 
     mod arith {
         use super::{_0, _1, _2, _1_2, _3_2, _neg1_2, to_big};
@@ -562,11 +573,11 @@ fn test(r: Rational, s: String) {
             assert_eq!(FromStr::from_str(s.as_slice()), Some(r));
             assert_eq!(r.to_str(), s);
         }
-        test(_1, "1/1".to_string());
-        test(_0, "0/1".to_string());
+        test(_1, "1".to_string());
+        test(_0, "0".to_string());
         test(_1_2, "1/2".to_string());
         test(_3_2, "3/2".to_string());
-        test(_2, "2/1".to_string());
+        test(_2, "2".to_string());
         test(_neg1_2, "-1/2".to_string());
     }
     #[test]
index 1400e207ab1a8615f73416d3fd7a7227bea279a1..cde83693f0b4174bd5da08b17ef876db97359739 100644 (file)
@@ -74,12 +74,12 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
     }
 }
 
-struct MatchCheckCtxt<'a> {
-    tcx: &'a ty::ctxt
+pub struct MatchCheckCtxt<'a> {
+    pub tcx: &'a ty::ctxt
 }
 
 #[deriving(Clone, PartialEq)]
-enum Constructor {
+pub enum Constructor {
     /// The constructor of all patterns that don't vary by constructor,
     /// e.g. struct patterns and fixed-length arrays.
     Single,
@@ -492,9 +492,9 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix, v: &[Gc<P
                          ctor: Constructor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
     let arity = constructor_arity(cx, &ctor, lty);
     let matrix = Matrix(m.iter().filter_map(|r| {
-        specialize(cx, r.as_slice(), &ctor, arity)
+        specialize(cx, r.as_slice(), &ctor, 0u, arity)
     }).collect());
-    match specialize(cx, v, &ctor, arity) {
+    match specialize(cx, v, &ctor, 0u, arity) {
         Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
         None => NotUseful
     }
@@ -580,7 +580,7 @@ fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
 ///
 /// For instance, a tuple pattern (_, 42u, Some([])) has the arity of 3.
 /// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
+pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
     match ty::get(ty).sty {
         ty::ty_tup(ref fs) => fs.len(),
         ty::ty_box(_) | ty::ty_uniq(_) => 1u,
@@ -628,11 +628,11 @@ fn range_covered_by_constructor(ctor: &Constructor,
 /// different patterns.
 /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
 /// fields filled with wild patterns.
-fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
-              constructor: &Constructor, arity: uint) -> Option<Vec<Gc<Pat>>> {
+pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
+                  constructor: &Constructor, col: uint, arity: uint) -> Option<Vec<Gc<Pat>>> {
     let &Pat {
         id: pat_id, node: ref node, span: pat_span
-    } = &(*raw_pat(r[0]));
+    } = &(*raw_pat(r[col]));
     let head: Option<Vec<Gc<Pat>>> = match node {
         &PatWild =>
             Some(Vec::from_elem(arity, wild())),
@@ -776,7 +776,7 @@ fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
             None
         }
     };
-    head.map(|head| head.append(r.tail()))
+    head.map(|head| head.append(r.slice_to(col)).append(r.slice_from(col + 1)))
 }
 
 fn default(cx: &MatchCheckCtxt, r: &[Gc<Pat>]) -> Option<Vec<Gc<Pat>>> {
index 20e4188a8f6c5cf01386610e71d9b435b0b4a968..186a737a56ba34f6cd0833d10d5894a050797f0a 100644 (file)
@@ -248,7 +248,6 @@ pub fn collect_language_items(krate: &ast::Crate,
     OrdTraitLangItem,                "ord",                     ord_trait;
 
     StrEqFnLangItem,                 "str_eq",                  str_eq_fn;
-    UniqStrEqFnLangItem,             "uniq_str_eq",             uniq_str_eq_fn;
 
     // A number of failure-related lang items. The `fail_` item corresponds to
     // divide-by-zero and various failure cases with `match`. The
index 091cfc706de6e385f5609c10caa105e1ac6677c9..310d0f19c329a391d88b7ec242f60021fd3daecb 100644 (file)
 use lib::llvm::{llvm, ValueRef, BasicBlockRef};
 use middle::const_eval;
 use middle::def;
-use middle::lang_items::{UniqStrEqFnLangItem, StrEqFnLangItem};
+use middle::check_match;
+use middle::lang_items::StrEqFnLangItem;
 use middle::pat_util::*;
 use middle::resolve::DefMap;
 use middle::trans::adt;
 use util::common::indenter;
 use util::ppaux::{Repr, vec_map_to_str};
 
+use std;
 use std::collections::HashMap;
 use std::cell::Cell;
 use std::rc::Rc;
-use std::gc::{Gc, GC};
+use std::gc::{Gc};
 use syntax::ast;
 use syntax::ast::Ident;
 use syntax::ast_util::path_to_ident;
 use syntax::ast_util;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
 
 // An option identifying a literal: either a unit-like struct or an
@@ -245,7 +247,7 @@ pub enum VecLenOpt {
 // range)
 enum Opt {
     lit(Lit),
-    var(ty::Disr, Rc<adt::Repr>),
+    var(ty::Disr, Rc<adt::Repr>, ast::DefId),
     range(Gc<ast::Expr>, Gc<ast::Expr>),
     vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
 }
@@ -277,7 +279,7 @@ fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
                 _ => fail!("compare_list_exprs: type mismatch"),
             }
         }
-        (&var(a, _), &var(b, _)) => a == b,
+        (&var(a, _, _), &var(b, _, _)) => a == b,
         (&vec_len(a1, a2, _), &vec_len(b1, b2, _)) =>
             a1 == b1 && a2 == b2,
         _ => false
@@ -313,7 +315,7 @@ fn trans_opt<'a>(bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
             let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
             return single_result(Result::new(bcx, lit_datum.val));
         }
-        var(disr_val, ref repr) => {
+        var(disr_val, ref repr, _) => {
             return adt::trans_case(bcx, &**repr, disr_val);
         }
         range(ref l1, ref l2) => {
@@ -335,18 +337,11 @@ fn variant_opt(bcx: &Block, pat_id: ast::NodeId) -> Opt {
     let def = ccx.tcx.def_map.borrow().get_copy(&pat_id);
     match def {
         def::DefVariant(enum_id, var_id, _) => {
-            let variants = ty::enum_variants(ccx.tcx(), enum_id);
-            for v in (*variants).iter() {
-                if var_id == v.id {
-                    return var(v.disr_val,
-                               adt::represent_node(bcx, pat_id))
-                }
-            }
-            unreachable!();
+            let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
+            var(variant.disr_val, adt::represent_node(bcx, pat_id), var_id)
         }
-        def::DefFn(..) |
-        def::DefStruct(_) => {
-            return lit(UnitLikeStructLit(pat_id));
+        def::DefFn(..) | def::DefStruct(_) => {
+            lit(UnitLikeStructLit(pat_id))
         }
         _ => {
             ccx.sess().bug("non-variant or struct in variant_opt()");
@@ -456,16 +451,7 @@ fn expand_nested_bindings<'a, 'b>(
     }).collect()
 }
 
-fn assert_is_binding_or_wild(bcx: &Block, p: Gc<ast::Pat>) {
-    if !pat_is_binding_or_wild(&bcx.tcx().def_map, &*p) {
-        bcx.sess().span_bug(
-            p.span,
-            format!("expected an identifier pattern but found p: {}",
-                    p.repr(bcx.tcx())).as_slice());
-    }
-}
-
-type enter_pat<'a> = |Gc<ast::Pat>|: 'a -> Option<Vec<Gc<ast::Pat>>>;
+type enter_pats<'a> = |&[Gc<ast::Pat>]|: 'a -> Option<Vec<Gc<ast::Pat>>>;
 
 fn enter_match<'a, 'b>(
                bcx: &'b Block<'b>,
@@ -473,7 +459,7 @@ fn enter_match<'a, 'b>(
                m: &'a [Match<'a, 'b>],
                col: uint,
                val: ValueRef,
-               e: enter_pat)
+               e: enter_pats)
                -> Vec<Match<'a, 'b>> {
     debug!("enter_match(bcx={}, m={}, col={}, val={})",
            bcx.to_str(),
@@ -483,10 +469,7 @@ fn enter_match<'a, 'b>(
     let _indenter = indenter();
 
     m.iter().filter_map(|br| {
-        e(*br.pats.get(col)).map(|sub| {
-            let pats = sub.append(br.pats.slice(0u, col))
-                            .append(br.pats.slice(col + 1u, br.pats.len()));
-
+        e(br.pats.as_slice()).map(|pats| {
             let this = *br.pats.get(col);
             let mut bound_ptrs = br.bound_ptrs.clone();
             match this.node {
@@ -522,11 +505,11 @@ fn enter_default<'a, 'b>(
     let _indenter = indenter();
 
     // Collect all of the matches that can match against anything.
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-          ast::PatWild | ast::PatWildMulti => Some(Vec::new()),
-          ast::PatIdent(_, _, None) if pat_is_binding(dm, &*p) => Some(Vec::new()),
-          _ => None
+    enter_match(bcx, dm, m, col, val, |pats| {
+        if pat_is_binding_or_wild(dm, pats[col]) {
+            Some(Vec::from_slice(pats.slice_to(col)).append(pats.slice_from(col + 1)))
+        } else {
+            None
         }
     })
 }
@@ -555,8 +538,14 @@ fn enter_default<'a, 'b>(
 // <nmatsakis> so all patterns must either be records (resp. tuples) or
 //             wildcards
 
+/// The above is now outdated in that enter_match() now takes a function that
+/// takes the complete row of patterns rather than just the first one.
+/// Also, most of the enter_() family functions have been unified with
+/// the check_match specialization step.
 fn enter_opt<'a, 'b>(
              bcx: &'b Block<'b>,
+             _: ast::NodeId,
+             dm: &DefMap,
              m: &'a [Match<'a, 'b>],
              opt: &Opt,
              col: uint,
@@ -571,88 +560,32 @@ fn enter_opt<'a, 'b>(
            bcx.val_to_str(val));
     let _indenter = indenter();
 
-    let tcx = bcx.tcx();
-    let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
-    let mut i = 0;
-    enter_match(bcx, &tcx.def_map, m, col, val, |p| {
-        let answer = match p.node {
-            ast::PatEnum(..) |
-            ast::PatIdent(_, _, None) if pat_is_const(&tcx.def_map, &*p) => {
-                let const_def = tcx.def_map.borrow().get_copy(&p.id);
-                let const_def_id = const_def.def_id();
-                if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) {
-                    Some(Vec::new())
-                } else {
-                    None
-                }
-            }
-            ast::PatEnum(_, ref subpats) => {
-                if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
-                    // FIXME: Must we clone?
-                    match *subpats {
-                        None => Some(Vec::from_elem(variant_size, dummy)),
-                        Some(ref subpats) => {
-                            Some((*subpats).iter().map(|x| *x).collect())
-                        }
-                    }
-                } else {
-                    None
-                }
-            }
-            ast::PatIdent(_, _, None)
-                    if pat_is_variant_or_struct(&tcx.def_map, &*p) => {
-                if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
-                    Some(Vec::new())
-                } else {
-                    None
-                }
-            }
-            ast::PatLit(l) => {
-                if opt_eq(tcx, &lit(ExprLit(l)), opt) { Some(Vec::new()) }
-                else { None }
-            }
-            ast::PatRange(l1, l2) => {
-                if opt_eq(tcx, &range(l1, l2), opt) { Some(Vec::new()) }
-                else { None }
-            }
-            ast::PatStruct(_, ref field_pats, _) => {
-                if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
-                    // Look up the struct variant ID.
-                    let struct_id;
-                    match tcx.def_map.borrow().get_copy(&p.id) {
-                        def::DefVariant(_, found_struct_id, _) => {
-                            struct_id = found_struct_id;
-                        }
-                        _ => {
-                            tcx.sess.span_bug(p.span, "expected enum variant def");
-                        }
-                    }
+    let ctor = match opt {
+        &lit(UnitLikeStructLit(_)) => check_match::Single,
+        &lit(x) => check_match::ConstantValue(const_eval::eval_const_expr(
+            bcx.tcx(), lit_to_expr(bcx.tcx(), &x))),
+        &range(ref lo, ref hi) => check_match::ConstantRange(
+            const_eval::eval_const_expr(bcx.tcx(), &**lo),
+            const_eval::eval_const_expr(bcx.tcx(), &**hi)
+        ),
+        &vec_len(len, _, _) => check_match::Slice(len),
+        &var(_, _, def_id) => check_match::Variant(def_id)
+    };
 
-                    // Reorder the patterns into the same order they were
-                    // specified in the struct definition. Also fill in
-                    // unspecified fields with dummy.
-                    let mut reordered_patterns = Vec::new();
-                    let r = ty::lookup_struct_fields(tcx, struct_id);
-                    for field in r.iter() {
-                            match field_pats.iter().find(|p| p.ident.name
-                                                         == field.name) {
-                                None => reordered_patterns.push(dummy),
-                                Some(fp) => reordered_patterns.push(fp.pat)
-                            }
-                    }
-                    Some(reordered_patterns)
-                } else {
-                    None
-                }
-            }
+    let mut i = 0;
+    let tcx = bcx.tcx();
+    let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+    enter_match(bcx, dm, m, col, val, |pats| {
+        let span = pats[col].span;
+        let specialized = match pats[col].node {
             ast::PatVec(ref before, slice, ref after) => {
                 let (lo, hi) = match *opt {
                     vec_len(_, _, (lo, hi)) => (lo, hi),
-                    _ => tcx.sess.span_bug(p.span,
+                    _ => tcx.sess.span_bug(span,
                                            "vec pattern but not vec opt")
                 };
 
-                match slice {
+                let elems = match slice {
                     Some(slice) if i >= lo && i <= hi => {
                         let n = before.len() + after.len();
                         let this_opt = vec_len(n, vec_len_ge(before.len()),
@@ -684,172 +617,15 @@ fn enter_opt<'a, 'b>(
                         }
                     }
                     _ => None
-                }
+                };
+                elems.map(|head| head.append(pats.slice_to(col)).append(pats.slice_from(col + 1)))
             }
             _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(Vec::from_elem(variant_size, dummy))
+                check_match::specialize(&mcx, pats.as_slice(), &ctor, col, variant_size)
             }
         };
         i += 1;
-        answer
-    })
-}
-
-fn enter_rec_or_struct<'a, 'b>(
-                       bcx: &'b Block<'b>,
-                       dm: &DefMap,
-                       m: &'a [Match<'a, 'b>],
-                       col: uint,
-                       fields: &[ast::Ident],
-                       val: ValueRef)
-                       -> Vec<Match<'a, 'b>> {
-    debug!("enter_rec_or_struct(bcx={}, m={}, col={}, val={})",
-           bcx.to_str(),
-           m.repr(bcx.tcx()),
-           col,
-           bcx.val_to_str(val));
-    let _indenter = indenter();
-
-    let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-            ast::PatStruct(_, ref fpats, _) => {
-                let mut pats = Vec::new();
-                for fname in fields.iter() {
-                    match fpats.iter().find(|p| p.ident.name == fname.name) {
-                        None => pats.push(dummy),
-                        Some(pat) => pats.push(pat.pat)
-                    }
-                }
-                Some(pats)
-            }
-            _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(Vec::from_elem(fields.len(), dummy))
-            }
-        }
-    })
-}
-
-fn enter_tup<'a, 'b>(
-             bcx: &'b Block<'b>,
-             dm: &DefMap,
-             m: &'a [Match<'a, 'b>],
-             col: uint,
-             val: ValueRef,
-             n_elts: uint)
-             -> Vec<Match<'a, 'b>> {
-    debug!("enter_tup(bcx={}, m={}, col={}, val={})",
-           bcx.to_str(),
-           m.repr(bcx.tcx()),
-           col,
-           bcx.val_to_str(val));
-    let _indenter = indenter();
-
-    let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-            ast::PatTup(ref elts) => {
-                let mut new_elts = Vec::new();
-                for elt in elts.iter() {
-                    new_elts.push((*elt).clone())
-                }
-                Some(new_elts)
-            }
-            _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(Vec::from_elem(n_elts, dummy))
-            }
-        }
-    })
-}
-
-fn enter_tuple_struct<'a, 'b>(
-                      bcx: &'b Block<'b>,
-                      dm: &DefMap,
-                      m: &'a [Match<'a, 'b>],
-                      col: uint,
-                      val: ValueRef,
-                      n_elts: uint)
-                      -> Vec<Match<'a, 'b>> {
-    debug!("enter_tuple_struct(bcx={}, m={}, col={}, val={})",
-           bcx.to_str(),
-           m.repr(bcx.tcx()),
-           col,
-           bcx.val_to_str(val));
-    let _indenter = indenter();
-
-    let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-            ast::PatEnum(_, Some(ref elts)) => {
-                Some(elts.iter().map(|x| (*x)).collect())
-            }
-            ast::PatEnum(_, None) => {
-                Some(Vec::from_elem(n_elts, dummy))
-            }
-            _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(Vec::from_elem(n_elts, dummy))
-            }
-        }
-    })
-}
-
-fn enter_uniq<'a, 'b>(
-              bcx: &'b Block<'b>,
-              dm: &DefMap,
-              m: &'a [Match<'a, 'b>],
-              col: uint,
-              val: ValueRef)
-              -> Vec<Match<'a, 'b>> {
-    debug!("enter_uniq(bcx={}, m={}, col={}, val={})",
-           bcx.to_str(),
-           m.repr(bcx.tcx()),
-           col,
-           bcx.val_to_str(val));
-    let _indenter = indenter();
-
-    let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-            ast::PatBox(sub) => {
-                Some(vec!(sub))
-            }
-            _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(vec!(dummy))
-            }
-        }
-    })
-}
-
-fn enter_region<'a, 'b>(
-                bcx: &'b Block<'b>,
-                dm: &DefMap,
-                m: &'a [Match<'a, 'b>],
-                col: uint,
-                val: ValueRef)
-                -> Vec<Match<'a, 'b>> {
-    debug!("enter_region(bcx={}, m={}, col={}, val={})",
-           bcx.to_str(),
-           m.repr(bcx.tcx()),
-           col,
-           bcx.val_to_str(val));
-    let _indenter = indenter();
-
-    let dummy = box(GC) ast::Pat { id: 0, node: ast::PatWild, span: DUMMY_SP };
-    enter_match(bcx, dm, m, col, val, |p| {
-        match p.node {
-            ast::PatRegion(sub) => {
-                Some(vec!(sub))
-            }
-            _ => {
-                assert_is_binding_or_wild(bcx, p);
-                Some(vec!(dummy))
-            }
-        }
+        specialized
     })
 }
 
@@ -894,14 +670,10 @@ fn add_veclen_to_set(set: &mut Vec<Opt> , i: uint,
                 // variable binding.
                 let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
                 match opt_def {
-                    Some(def::DefVariant(..)) => {
+                    Some(def::DefVariant(..)) | Some(def::DefStruct(..)) => {
                         add_to_set(ccx.tcx(), &mut found,
                                    variant_opt(bcx, cur.id));
                     }
-                    Some(def::DefStruct(..)) => {
-                        add_to_set(ccx.tcx(), &mut found,
-                                   lit(UnitLikeStructLit(cur.id)));
-                    }
                     Some(def::DefStatic(const_did, false)) => {
                         add_to_set(ccx.tcx(), &mut found,
                                    lit(ConstLit(const_did)));
@@ -1021,49 +793,6 @@ fn extract_vec_elems<'a>(
     ExtractedBlock { vals: elems, bcx: bcx }
 }
 
-/// Checks every pattern in `m` at `col` column.
-/// If there are a struct pattern among them function
-/// returns list of all fields that are matched in these patterns.
-/// Function returns None if there is no struct pattern.
-/// Function doesn't collect fields from struct-like enum variants.
-/// Function can return empty list if there is only wildcard struct pattern.
-fn collect_record_or_struct_fields<'a>(
-                                   bcx: &'a Block<'a>,
-                                   m: &[Match],
-                                   col: uint)
-                                   -> Option<Vec<ast::Ident> > {
-    let mut fields: Vec<ast::Ident> = Vec::new();
-    let mut found = false;
-    for br in m.iter() {
-        match br.pats.get(col).node {
-          ast::PatStruct(_, ref fs, _) => {
-            match ty::get(node_id_type(bcx, br.pats.get(col).id)).sty {
-              ty::ty_struct(..) => {
-                   extend(&mut fields, fs.as_slice());
-                   found = true;
-              }
-              _ => ()
-            }
-          }
-          _ => ()
-        }
-    }
-    if found {
-        return Some(fields);
-    } else {
-        return None;
-    }
-
-    fn extend(idents: &mut Vec<ast::Ident> , field_pats: &[ast::FieldPat]) {
-        for field_pat in field_pats.iter() {
-            let field_ident = field_pat.ident;
-            if !idents.iter().any(|x| x.name == field_ident.name) {
-                idents.push(field_ident);
-            }
-        }
-    }
-}
-
 // Macro for deciding whether any of the remaining matches fit a given kind of
 // pattern.  Note that, because the macro is well-typed, either ALL of the
 // matches should fit that sort of pattern or NONE (however, some of the
@@ -1087,21 +816,17 @@ fn any_region_pat(m: &[Match], col: uint) -> bool {
     any_pat!(m, ast::PatRegion(_))
 }
 
-fn any_tup_pat(m: &[Match], col: uint) -> bool {
-    any_pat!(m, ast::PatTup(_))
-}
-
-fn any_tuple_struct_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
+fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
     m.iter().any(|br| {
         let pat = *br.pats.get(col);
         match pat.node {
-            ast::PatEnum(_, _) => {
+            ast::PatTup(_) => true,
+            ast::PatStruct(_, _, _) | ast::PatEnum(_, _) =>
                 match bcx.tcx().def_map.borrow().find(&pat.id) {
                     Some(&def::DefFn(..)) |
                     Some(&def::DefStruct(..)) => true,
                     _ => false
-                }
-            }
+                },
             _ => false
         }
     })
@@ -1191,7 +916,7 @@ fn score(p: &ast::Pat) -> uint {
 }
 
 #[deriving(PartialEq)]
-pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, }
+pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len }
 
 // Compiles a comparison between two things.
 fn compare_values<'a>(
@@ -1220,21 +945,6 @@ fn compare_str<'a>(cx: &'a Block<'a>,
     }
 
     match ty::get(rhs_t).sty {
-        ty::ty_uniq(t) => match ty::get(t).sty {
-            ty::ty_str => {
-                let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs");
-                Store(cx, lhs, scratch_lhs);
-                let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs");
-                Store(cx, rhs, scratch_rhs);
-                let did = langcall(cx,
-                                   None,
-                                   format!("comparison of `{}`",
-                                           cx.ty_to_str(rhs_t)).as_slice(),
-                                   UniqStrEqFnLangItem);
-                callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None)
-            }
-            _ => cx.sess().bug("only strings supported in compare_values"),
-        },
         ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
             ty::ty_str => compare_str(cx, lhs, rhs, rhs_t),
             ty::ty_vec(mt, _) => match ty::get(mt.ty).sty {
@@ -1248,7 +958,7 @@ fn compare_str<'a>(cx: &'a Block<'a>,
                 },
                 _ => cx.sess().bug("only byte strings supported in compare_values"),
             },
-            _ => cx.sess().bug("on string and byte strings supported in compare_values"),
+            _ => cx.sess().bug("only string and byte strings supported in compare_values"),
         },
         _ => cx.sess().bug("only scalars, byte strings, and strings supported in compare_values"),
     }
@@ -1410,103 +1120,41 @@ fn compile_submatch_continue<'a, 'b>(
 
     let vals_left = Vec::from_slice(vals.slice(0u, col)).append(vals.slice(col + 1u, vals.len()));
     let ccx = bcx.fcx.ccx;
-    let mut pat_id = 0;
-    for br in m.iter() {
-        // Find a real id (we're adding placeholder wildcard patterns, but
-        // each column is guaranteed to have at least one real pattern)
-        if pat_id == 0 {
-            pat_id = br.pats.get(col).id;
-        }
-    }
-
-    match collect_record_or_struct_fields(bcx, m, col) {
-        Some(ref rec_fields) => {
-            let pat_ty = node_id_type(bcx, pat_id);
-            let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
-            expr::with_field_tys(tcx, pat_ty, Some(pat_id), |discr, field_tys| {
-                let rec_vals = rec_fields.iter().map(|field_name| {
-                        let ix = ty::field_idx_strict(tcx, field_name.name, field_tys);
-                        adt::trans_field_ptr(bcx, &*pat_repr, val, discr, ix)
-                        }).collect::<Vec<_>>();
-                compile_submatch(
-                        bcx,
-                        enter_rec_or_struct(bcx,
-                                            dm,
-                                            m,
-                                            col,
-                                            rec_fields.as_slice(),
-                                            val).as_slice(),
-                        rec_vals.append(vals_left.as_slice()).as_slice(),
-                        chk, has_genuine_default);
-            });
-            return;
-        }
-        None => {}
-    }
 
-    if any_tup_pat(m, col) {
-        let tup_ty = node_id_type(bcx, pat_id);
-        let tup_repr = adt::represent_type(bcx.ccx(), tup_ty);
-        let n_tup_elts = match ty::get(tup_ty).sty {
-          ty::ty_tup(ref elts) => elts.len(),
-          _ => ccx.sess().bug("non-tuple type in tuple pattern")
-        };
-        let tup_vals = Vec::from_fn(n_tup_elts, |i| {
-            adt::trans_field_ptr(bcx, &*tup_repr, val, 0, i)
-        });
-        compile_submatch(bcx,
-                         enter_tup(bcx,
-                                   dm,
-                                   m,
-                                   col,
-                                   val,
-                                   n_tup_elts).as_slice(),
-                         tup_vals.append(vals_left.as_slice()).as_slice(),
-                         chk, has_genuine_default);
-        return;
-    }
+    // Find a real id (we're adding placeholder wildcard patterns, but
+    // each column is guaranteed to have at least one real pattern)
+    let pat_id = m.iter().map(|br| br.pats.get(col).id).find(|&id| id != 0).unwrap_or(0);
 
-    if any_tuple_struct_pat(bcx, m, col) {
-        let struct_ty = node_id_type(bcx, pat_id);
-        let struct_element_count;
-        match ty::get(struct_ty).sty {
-            ty::ty_struct(struct_id, _) => {
-                struct_element_count =
-                    ty::lookup_struct_fields(tcx, struct_id).len();
-            }
-            _ => {
-                ccx.sess().bug("non-struct type in tuple struct pattern");
-            }
-        }
-
-        let struct_repr = adt::represent_type(bcx.ccx(), struct_ty);
-        let llstructvals = Vec::from_fn(struct_element_count, |i| {
-            adt::trans_field_ptr(bcx, &*struct_repr, val, 0, i)
-        });
-        compile_submatch(bcx,
-                         enter_tuple_struct(bcx, dm, m, col, val,
-                                            struct_element_count).as_slice(),
-                         llstructvals.append(vals_left.as_slice()).as_slice(),
-                         chk, has_genuine_default);
-        return;
-    }
+    let left_ty = if pat_id == 0 {
+        ty::mk_nil()
+    } else {
+        node_id_type(bcx, pat_id)
+    };
 
-    if any_uniq_pat(m, col) {
-        let llbox = Load(bcx, val);
-        compile_submatch(bcx,
-                         enter_uniq(bcx, dm, m, col, val).as_slice(),
-                         (vec!(llbox)).append(vals_left.as_slice()).as_slice(),
-                         chk, has_genuine_default);
-        return;
-    }
+    let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+    let adt_vals = if any_irrefutable_adt_pat(bcx, m, col) {
+        let repr = adt::represent_type(bcx.ccx(), left_ty);
+        let arg_count = adt::num_args(&*repr, 0);
+        let field_vals: Vec<ValueRef> = std::iter::range(0, arg_count).map(|ix|
+            adt::trans_field_ptr(bcx, &*repr, val, 0, ix)
+        ).collect();
+        Some(field_vals)
+    } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
+        Some(vec!(Load(bcx, val)))
+    } else {
+        None
+    };
 
-    if any_region_pat(m, col) {
-        let loaded_val = Load(bcx, val);
-        compile_submatch(bcx,
-                         enter_region(bcx, dm, m, col, val).as_slice(),
-                         (vec!(loaded_val)).append(vals_left.as_slice()).as_slice(),
-                         chk, has_genuine_default);
-        return;
+    match adt_vals {
+        Some(field_vals) => {
+            let pats = enter_match(bcx, dm, m, col, val, |pats|
+                check_match::specialize(&mcx, pats, &check_match::Single, col, field_vals.len())
+            );
+            let vals = field_vals.append(vals_left.as_slice());
+            compile_submatch(bcx, pats.as_slice(), vals.as_slice(), chk, has_genuine_default);
+            return;
+        }
+        _ => ()
     }
 
     // Decide what kind of branch we need
@@ -1517,15 +1165,14 @@ fn compile_submatch_continue<'a, 'b>(
     debug!("test_val={}", bcx.val_to_str(test_val));
     if opts.len() > 0u {
         match *opts.get(0) {
-            var(_, ref repr) => {
+            var(_, ref repr, _) => {
                 let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val);
                 kind = the_kind;
                 for &tval in val_opt.iter() { test_val = tval; }
             }
             lit(_) => {
-                let pty = node_id_type(bcx, pat_id);
-                test_val = load_if_immediate(bcx, val, pty);
-                kind = if ty::type_is_integral(pty) { switch }
+                test_val = load_if_immediate(bcx, val, left_ty);
+                kind = if ty::type_is_integral(left_ty) { switch }
                 else { compare };
             }
             range(_, _) => {
@@ -1533,8 +1180,7 @@ fn compile_submatch_continue<'a, 'b>(
                 kind = compare;
             },
             vec_len(..) => {
-                let vec_ty = node_id_type(bcx, pat_id);
-                let (_, len) = tvec::get_base_and_len(bcx, val, vec_ty);
+                let (_, len) = tvec::get_base_and_len(bcx, val, left_ty);
                 test_val = len;
                 kind = compare_vec_len;
             }
@@ -1587,17 +1233,19 @@ fn compile_submatch_continue<'a, 'b>(
                       }
                   }
               }
-              compare => {
-                  let t = node_id_type(bcx, pat_id);
+              compare | compare_vec_len => {
+                  let t = if kind == compare {
+                      left_ty
+                  } else {
+                      ty::mk_uint() // vector length
+                  };
                   let Result {bcx: after_cx, val: matches} = {
                       match trans_opt(bcx, opt) {
                           single_result(Result {bcx, val}) => {
                               compare_values(bcx, test_val, val, t)
                           }
                           lower_bound(Result {bcx, val}) => {
-                              compare_scalar_types(
-                                  bcx, test_val, val,
-                                  t, ast::BiGe)
+                              compare_scalar_types(bcx, test_val, val, t, ast::BiGe)
                           }
                           range_result(Result {val: vbegin, ..},
                                        Result {bcx, val: vend}) => {
@@ -1621,48 +1269,7 @@ fn compile_submatch_continue<'a, 'b>(
                   // the default.
                   let guarded = m[i].data.arm.guard.is_some();
                   let multi_pats = m[i].pats.len() > 1;
-                  if i+1 < len && (guarded || multi_pats) {
-                      branch_chk = Some(JumpToBasicBlock(bcx.llbb));
-                  }
-                  CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
-              }
-              compare_vec_len => {
-                  let Result {bcx: after_cx, val: matches} = {
-                      match trans_opt(bcx, opt) {
-                          single_result(
-                              Result {bcx, val}) => {
-                              let value = compare_scalar_values(
-                                  bcx, test_val, val,
-                                  signed_int, ast::BiEq);
-                              Result::new(bcx, value)
-                          }
-                          lower_bound(
-                              Result {bcx, val: val}) => {
-                              let value = compare_scalar_values(
-                                  bcx, test_val, val,
-                                  signed_int, ast::BiGe);
-                              Result::new(bcx, value)
-                          }
-                          range_result(
-                              Result {val: vbegin, ..},
-                              Result {bcx, val: vend}) => {
-                              let llge =
-                                  compare_scalar_values(
-                                  bcx, test_val,
-                                  vbegin, signed_int, ast::BiGe);
-                              let llle =
-                                  compare_scalar_values(
-                                  bcx, test_val, vend,
-                                  signed_int, ast::BiLe);
-                              Result::new(bcx, And(bcx, llge, llle))
-                          }
-                      }
-                  };
-                  bcx = fcx.new_temp_block("compare_vec_len_next");
-
-                  // If none of these subcases match, move on to the
-                  // next condition if there is any.
-                  if i+1 < len {
+                  if i + 1 < len && (guarded || multi_pats || kind == compare_vec_len) {
                       branch_chk = Some(JumpToBasicBlock(bcx.llbb));
                   }
                   CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
@@ -1676,7 +1283,7 @@ fn compile_submatch_continue<'a, 'b>(
         let mut size = 0u;
         let mut unpacked = Vec::new();
         match *opt {
-            var(disr_val, ref repr) => {
+            var(disr_val, ref repr, _) => {
                 let ExtractedBlock {vals: argvals, bcx: new_bcx} =
                     extract_variant_args(opt_cx, &**repr, disr_val, val);
                 size = argvals.len();
@@ -1696,7 +1303,7 @@ fn compile_submatch_continue<'a, 'b>(
             }
             lit(_) | range(_, _) => ()
         }
-        let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
+        let opt_ms = enter_opt(opt_cx, pat_id, dm, m, opt, col, size, val);
         let opt_vals = unpacked.append(vals_left.as_slice());
 
         match branch_chk {
index 116b2e6b421b81e41e1c5a94064853528c57897a..0cc4a9223d49963bd0909253711d2f3c3d8fb806 100644 (file)
@@ -261,7 +261,7 @@ pub fn trans_unboxing_shim(bcx: &Block,
     let function_type =
         ty::mk_bare_fn(tcx, method.fty.clone()).subst(tcx, &substs);
 
-    let function_name = tcx.map.with_path(method_id.node, |path| {
+    let function_name = ty::with_path(tcx, method_id, |path| {
         link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim")
     });
     let llfn = decl_internal_rust_fn(ccx,
index 83b956290ef696bf5e3ee4401886439c12104570..1c48d66f9b81e78cfc409824cdd582050a9e91ac 100644 (file)
@@ -222,6 +222,13 @@ struct List {
 static DW_ATE_unsigned: c_uint = 0x07;
 static DW_ATE_unsigned_char: c_uint = 0x08;
 
+static UNKNOWN_LINE_NUMBER: c_uint = 0;
+static UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+
+// ptr::null() doesn't work :(
+static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
+static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
+
 //=-----------------------------------------------------------------------------
 //  Public Interface of debuginfo module
 //=-----------------------------------------------------------------------------
@@ -330,15 +337,15 @@ fn get_unique_type_id_of_type(&mut self, cx: &CrateContext, type_: ty::t) -> Uni
         unique_type_id.push_char('{');
 
         match ty::get(type_).sty {
-            ty::ty_nil                |
-            ty::ty_bot                |
-            ty::ty_bool               |
-            ty::ty_char               |
-            ty::ty_str                |
-            ty::ty_int(_)             |
-            ty::ty_uint(_)            |
+            ty::ty_nil      |
+            ty::ty_bot      |
+            ty::ty_bool     |
+            ty::ty_char     |
+            ty::ty_str      |
+            ty::ty_int(_)   |
+            ty::ty_uint(_)  |
             ty::ty_float(_) => {
-                unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
+                push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
             },
             ty::ty_enum(def_id, ref substs) => {
                 unique_type_id.push_str("enum ");
@@ -587,7 +594,7 @@ fn get_unique_type_id_of_heap_vec_box(&mut self,
                                           element_type: ty::t)
                                        -> UniqueTypeId {
         let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
-        let heap_vec_box_type_id = format!("$$HEAP_VEC_BOX<{}>$$",
+        let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}",
                                            self.get_unique_type_id_as_string(element_type_id)
                                                .as_slice());
         let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id));
@@ -599,7 +606,7 @@ fn get_unique_type_id_of_gc_box(&mut self,
                                     element_type: ty::t)
                                  -> UniqueTypeId {
         let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
-        let gc_box_type_id = format!("$$GC_BOX<{}>$$",
+        let gc_box_type_id = format!("{{GC_BOX<{}>}}",
                                      self.get_unique_type_id_as_string(element_type_id)
                                          .as_slice());
         let interner_key = self.unique_id_interner.intern(Rc::new(gc_box_type_id));
@@ -607,6 +614,19 @@ fn get_unique_type_id_of_gc_box(&mut self,
     }
 }
 
+// Returns from the enclosing function if the type metadata with the given
+// unique id can be found in the type map
+macro_rules! return_if_metadata_created_in_meantime(
+    ($cx: expr, $unique_type_id: expr) => (
+        match debug_context($cx).type_map
+                                .borrow()
+                                .find_metadata_for_unique_id($unique_type_id) {
+            Some(metadata) => return MetadataCreationResult::new(metadata, true),
+            None => { /* proceed normally */ }
+        };
+    )
+)
+
 
 /// A context object for maintaining all state needed by the debuginfo module.
 pub struct CrateDebugContext {
@@ -1321,9 +1341,12 @@ fn get_template_parameters(cx: &CrateContext,
         if has_self_type {
             let actual_self_type = self_type.unwrap();
             // Add self type name to <...> clause of function name
-            let actual_self_type_name = ppaux::ty_to_str(cx.tcx(), actual_self_type);
-            name_to_append_suffix_to.push_str(
-                actual_self_type_name.as_slice());
+            let actual_self_type_name = compute_debuginfo_type_name(
+                cx,
+                actual_self_type,
+                true);
+
+            name_to_append_suffix_to.push_str(actual_self_type_name.as_slice());
 
             if generics.is_type_parameterized() {
                 name_to_append_suffix_to.push_str(",");
@@ -1360,7 +1383,9 @@ fn get_template_parameters(cx: &CrateContext,
         for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() {
             let actual_type = *actual_types.get(index);
             // Add actual type name to <...> clause of function name
-            let actual_type_name = ppaux::ty_to_str(cx.tcx(), actual_type);
+            let actual_type_name = compute_debuginfo_type_name(cx,
+                                                               actual_type,
+                                                               true);
             name_to_append_suffix_to.push_str(actual_type_name.as_slice());
 
             if index != generics.ty_params.len() - 1 {
@@ -1663,7 +1688,7 @@ fn pointer_type_metadata(cx: &CrateContext,
                       -> DIType {
     let pointer_llvm_type = type_of::type_of(cx, pointer_type);
     let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
-    let name = ppaux::ty_to_str(cx.tcx(), pointer_type);
+    let name = compute_debuginfo_type_name(cx, pointer_type, false);
     let ptr_metadata = name.as_slice().with_c_str(|name| {
         unsafe {
             llvm::LLVMDIBuilderCreatePointerType(
@@ -1736,7 +1761,6 @@ enum RecursiveTypeDescription {
         unique_type_id: UniqueTypeId,
         metadata_stub: DICompositeType,
         llvm_type: Type,
-        file_metadata: DIFile,
         member_description_factory: MemberDescriptionFactory,
     },
     FinalMetadata(DICompositeType)
@@ -1748,7 +1772,6 @@ fn create_and_register_recursive_type_forward_declaration(
     unique_type_id: UniqueTypeId,
     metadata_stub: DICompositeType,
     llvm_type: Type,
-    file_metadata: DIFile,
     member_description_factory: MemberDescriptionFactory)
  -> RecursiveTypeDescription {
 
@@ -1762,7 +1785,6 @@ fn create_and_register_recursive_type_forward_declaration(
         unique_type_id: unique_type_id,
         metadata_stub: metadata_stub,
         llvm_type: llvm_type,
-        file_metadata: file_metadata,
         member_description_factory: member_description_factory,
     }
 }
@@ -1778,8 +1800,8 @@ fn finalize(&self, cx: &CrateContext) -> MetadataCreationResult {
                 unique_type_id,
                 metadata_stub,
                 llvm_type,
-                file_metadata,
-                ref member_description_factory
+                ref member_description_factory,
+                ..
             } => {
                 // Make sure that we have a forward declaration of the type in
                 // the TypeMap so that recursive references are possible. This
@@ -1805,9 +1827,7 @@ fn finalize(&self, cx: &CrateContext) -> MetadataCreationResult {
                 set_members_of_composite_type(cx,
                                               metadata_stub,
                                               llvm_type,
-                                              member_descriptions.as_slice(),
-                                              file_metadata,
-                                              codemap::DUMMY_SP);
+                                              member_descriptions.as_slice());
                 return MetadataCreationResult::new(metadata_stub, true);
             }
         }
@@ -1862,6 +1882,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
     }
 }
 
+
 fn prepare_struct_metadata(cx: &CrateContext,
                            struct_type: ty::t,
                            def_id: ast::DefId,
@@ -1869,21 +1890,16 @@ fn prepare_struct_metadata(cx: &CrateContext,
                            unique_type_id: UniqueTypeId,
                            span: Span)
                         -> RecursiveTypeDescription {
-    let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
+    let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
     let struct_llvm_type = type_of::type_of(cx, struct_type);
 
-    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);
-
-    let file_name = span_start(cx, definition_span).file.name.clone();
-    let file_metadata = file_metadata(cx, file_name.as_slice());
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
 
     let struct_metadata_stub = create_struct_stub(cx,
                                                   struct_llvm_type,
                                                   struct_name.as_slice(),
                                                   unique_type_id,
-                                                  containing_scope,
-                                                  file_metadata,
-                                                  definition_span);
+                                                  containing_scope);
 
     let fields = ty::struct_fields(cx.tcx(), def_id, substs);
 
@@ -1893,7 +1909,6 @@ fn prepare_struct_metadata(cx: &CrateContext,
         unique_type_id,
         struct_metadata_stub,
         struct_llvm_type,
-        file_metadata,
         StructMDF(StructMemberDescriptionFactory {
             fields: fields,
             is_simd: ty::type_is_simd(cx.tcx(), struct_type),
@@ -1933,12 +1948,9 @@ fn prepare_tuple_metadata(cx: &CrateContext,
                           unique_type_id: UniqueTypeId,
                           span: Span)
                        -> RecursiveTypeDescription {
-    let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
+    let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
     let tuple_llvm_type = type_of::type_of(cx, tuple_type);
 
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
     create_and_register_recursive_type_forward_declaration(
         cx,
         tuple_type,
@@ -1947,11 +1959,8 @@ fn prepare_tuple_metadata(cx: &CrateContext,
                            tuple_llvm_type,
                            tuple_name.as_slice(),
                            unique_type_id,
-                           file_metadata,
-                           file_metadata,
-                           span),
+                           UNKNOWN_SCOPE_METADATA),
         tuple_llvm_type,
-        file_metadata,
         TupleMDF(TupleMemberDescriptionFactory {
             component_types: Vec::from_slice(component_types),
             span: span,
@@ -1999,7 +2008,6 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                                                   &**self.variants.get(i),
                                                   discriminant_info,
                                                   self.containing_scope,
-                                                  self.file_metadata,
                                                   self.span);
 
                         let member_descriptions = member_desc_factory
@@ -2008,9 +2016,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                         set_members_of_composite_type(cx,
                                                       variant_type_metadata,
                                                       variant_llvm_type,
-                                                      member_descriptions.as_slice(),
-                                                      self.file_metadata,
-                                                      codemap::DUMMY_SP);
+                                                      member_descriptions.as_slice());
                         MemberDescription {
                             name: "".to_string(),
                             llvm_type: variant_llvm_type,
@@ -2034,7 +2040,6 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                                               &**self.variants.get(0),
                                               NoDiscriminant,
                                               self.containing_scope,
-                                              self.file_metadata,
                                               self.span);
 
                     let member_descriptions =
@@ -2043,9 +2048,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                     set_members_of_composite_type(cx,
                                                   variant_type_metadata,
                                                   variant_llvm_type,
-                                                  member_descriptions.as_slice(),
-                                                  self.file_metadata,
-                                                  codemap::DUMMY_SP);
+                                                  member_descriptions.as_slice());
                     vec![
                         MemberDescription {
                             name: "".to_string(),
@@ -2136,7 +2139,6 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                                           &**self.variants.get(nndiscr as uint),
                                           OptimizedDiscriminant(ptrfield),
                                           self.containing_scope,
-                                          self.file_metadata,
                                           self.span);
 
                 let variant_member_descriptions =
@@ -2145,9 +2147,7 @@ fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription
                 set_members_of_composite_type(cx,
                                               variant_type_metadata,
                                               variant_llvm_type,
-                                              variant_member_descriptions.as_slice(),
-                                              self.file_metadata,
-                                              codemap::DUMMY_SP);
+                                              variant_member_descriptions.as_slice());
 
                 // Encode the information about the null variant in the union
                 // member's name.
@@ -2212,7 +2212,6 @@ fn describe_enum_variant(cx: &CrateContext,
                          variant_info: &ty::VariantInfo,
                          discriminant_info: EnumDiscriminantInfo,
                          containing_scope: DIScope,
-                         file_metadata: DIFile,
                          span: Span)
                       -> (DICompositeType, Type, MemberDescriptionFactory) {
     let variant_llvm_type =
@@ -2224,14 +2223,6 @@ fn describe_enum_variant(cx: &CrateContext,
                       struct_def.packed);
     // Could do some consistency checks here: size, align, field count, discr type
 
-    // Find the source code location of the variant's definition
-    let variant_definition_span = if variant_info.id.krate == ast::LOCAL_CRATE {
-        cx.tcx.map.span(variant_info.id.node)
-    } else {
-        // For definitions from other crates we have no location information available.
-        codemap::DUMMY_SP
-    };
-
     let variant_name = token::get_ident(variant_info.name);
     let variant_name = variant_name.get();
     let unique_type_id = debug_context(cx).type_map
@@ -2245,9 +2236,7 @@ fn describe_enum_variant(cx: &CrateContext,
                                            variant_llvm_type,
                                            variant_name,
                                            unique_type_id,
-                                           containing_scope,
-                                           file_metadata,
-                                           variant_definition_span);
+                                           containing_scope);
 
     // Get the argument names from the enum variant info
     let mut arg_names: Vec<_> = match variant_info.arg_names {
@@ -2293,7 +2282,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
                          unique_type_id: UniqueTypeId,
                          span: Span)
                       -> RecursiveTypeDescription {
-    let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
+    let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
 
     let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, enum_def_id);
     let loc = span_start(cx, definition_span);
@@ -2340,8 +2329,8 @@ fn prepare_enum_metadata(cx: &CrateContext,
                             DIB(cx),
                             containing_scope,
                             name,
-                            file_metadata,
-                            loc.line as c_uint,
+                            UNKNOWN_FILE_METADATA,
+                            UNKNOWN_LINE_NUMBER,
                             bytes_to_bits(discriminant_size),
                             bytes_to_bits(discriminant_align),
                             create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
@@ -2385,8 +2374,8 @@ fn prepare_enum_metadata(cx: &CrateContext,
                 DIB(cx),
                 containing_scope,
                 enum_name,
-                file_metadata,
-                loc.line as c_uint,
+                UNKNOWN_FILE_METADATA,
+                UNKNOWN_LINE_NUMBER,
                 bytes_to_bits(enum_type_size),
                 bytes_to_bits(enum_type_align),
                 0, // Flags
@@ -2403,7 +2392,6 @@ fn prepare_enum_metadata(cx: &CrateContext,
         unique_type_id,
         enum_metadata,
         enum_llvm_type,
-        file_metadata,
         EnumMDF(EnumMemberDescriptionFactory {
             enum_type: enum_type,
             type_rep: type_rep.clone(),
@@ -2438,24 +2426,23 @@ fn composite_type_metadata(cx: &CrateContext,
                            composite_type_unique_id: UniqueTypeId,
                            member_descriptions: &[MemberDescription],
                            containing_scope: DIScope,
-                           file_metadata: DIFile,
-                           definition_span: Span)
+
+                           // Ignore source location information as long as it
+                           // can't be reconstructed for non-local crates.
+                           _file_metadata: DIFile,
+                           _definition_span: Span)
                         -> DICompositeType {
     // Create the (empty) struct metadata node ...
     let composite_type_metadata = create_struct_stub(cx,
                                                      composite_llvm_type,
                                                      composite_type_name,
                                                      composite_type_unique_id,
-                                                     containing_scope,
-                                                     file_metadata,
-                                                     definition_span);
+                                                     containing_scope);
     // ... and immediately create and add the member descriptions.
     set_members_of_composite_type(cx,
                                   composite_type_metadata,
                                   composite_llvm_type,
-                                  member_descriptions,
-                                  file_metadata,
-                                  definition_span);
+                                  member_descriptions);
 
     return composite_type_metadata;
 }
@@ -2463,9 +2450,7 @@ fn composite_type_metadata(cx: &CrateContext,
 fn set_members_of_composite_type(cx: &CrateContext,
                                  composite_type_metadata: DICompositeType,
                                  composite_llvm_type: Type,
-                                 member_descriptions: &[MemberDescription],
-                                 file_metadata: DIFile,
-                                 definition_span: Span) {
+                                 member_descriptions: &[MemberDescription]) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in create_struct_stub.
     // This would cause a hard to trace assertion in DICompositeType::SetTypeArray().
@@ -2500,8 +2485,6 @@ fn set_members_of_composite_type(cx: &CrateContext,
         }
     }
 
-    let loc = span_start(cx, definition_span);
-
     let member_metadata: Vec<DIDescriptor> = member_descriptions
         .iter()
         .enumerate()
@@ -2518,8 +2501,8 @@ fn set_members_of_composite_type(cx: &CrateContext,
                         DIB(cx),
                         composite_type_metadata,
                         member_name,
-                        file_metadata,
-                        loc.line as c_uint,
+                        UNKNOWN_FILE_METADATA,
+                        UNKNOWN_LINE_NUMBER,
                         bytes_to_bits(member_size),
                         bytes_to_bits(member_align),
                         bytes_to_bits(member_offset),
@@ -2543,11 +2526,8 @@ fn create_struct_stub(cx: &CrateContext,
                       struct_llvm_type: Type,
                       struct_type_name: &str,
                       unique_type_id: UniqueTypeId,
-                      containing_scope: DIScope,
-                      file_metadata: DIFile,
-                      definition_span: Span)
+                      containing_scope: DIScope)
                    -> DICompositeType {
-    let loc = span_start(cx, definition_span);
     let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
 
     let unique_type_id_str = debug_context(cx).type_map
@@ -2565,8 +2545,8 @@ fn create_struct_stub(cx: &CrateContext,
                     DIB(cx),
                     containing_scope,
                     name,
-                    file_metadata,
-                    loc.line as c_uint,
+                    UNKNOWN_FILE_METADATA,
+                    UNKNOWN_LINE_NUMBER,
                     bytes_to_bits(struct_size),
                     bytes_to_bits(struct_align),
                     0,
@@ -2589,12 +2569,9 @@ fn at_box_metadata(cx: &CrateContext,
                 -> MetadataCreationResult {
     let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
-    let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
+    let content_type_name = compute_debuginfo_type_name(cx, content_type, true);
     let content_type_name = content_type_name.as_slice();
     let content_llvm_type = type_of::type_of(cx, content_type);
 
@@ -2610,7 +2587,6 @@ fn at_box_metadata(cx: &CrateContext,
     let nil_pointer_type_metadata = type_metadata(cx,
                                                   nil_pointer_type,
                                                   codemap::DUMMY_SP);
-
     let member_descriptions = [
         MemberDescription {
             name: "refcnt".to_string(),
@@ -2644,9 +2620,6 @@ fn at_box_metadata(cx: &CrateContext,
         }
     ];
 
-    let loc = span_start(cx, codemap::DUMMY_SP);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
     let gc_box_unique_id = debug_context(cx).type_map
                                             .borrow_mut()
                                             .get_unique_type_id_of_gc_box(cx, content_type);
@@ -2657,8 +2630,8 @@ fn at_box_metadata(cx: &CrateContext,
         box_type_name.as_slice(),
         gc_box_unique_id,
         member_descriptions,
-        file_metadata,
-        file_metadata,
+        UNKNOWN_SCOPE_METADATA,
+        UNKNOWN_FILE_METADATA,
         codemap::DUMMY_SP);
 
     let gc_pointer_metadata = pointer_type_metadata(cx,
@@ -2691,10 +2664,7 @@ fn fixed_vec_metadata(cx: &CrateContext,
                    -> MetadataCreationResult {
     let element_type_metadata = type_metadata(cx, element_type, span);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let element_llvm_type = type_of::type_of(cx, element_type);
     let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
@@ -2729,13 +2699,12 @@ fn heap_vec_metadata(cx: &CrateContext,
     let element_llvm_type = type_of::type_of(cx, element_type);
     let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
-    let vec_pointer_type_name = ppaux::ty_to_str(cx.tcx(), vec_pointer_type);
+    let vec_pointer_type_name = compute_debuginfo_type_name(cx,
+                                                            vec_pointer_type,
+                                                            true);
     let vec_pointer_type_name = vec_pointer_type_name.as_slice();
 
     let member_llvm_types = vecbox_llvm_type.field_types();
@@ -2786,7 +2755,7 @@ fn heap_vec_metadata(cx: &CrateContext,
                                                   vec_pointer_type_name,
                                                   vec_box_unique_id,
                                                   member_descriptions,
-                                                  file_metadata,
+                                                  UNKNOWN_SCOPE_METADATA,
                                                   file_metadata,
                                                   span);
 
@@ -2808,13 +2777,10 @@ fn vec_slice_metadata(cx: &CrateContext,
 
     let element_type_metadata = type_metadata(cx, data_ptr_type, span);
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     let slice_llvm_type = type_of::type_of(cx, vec_type);
-    let slice_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
+    let slice_type_name = compute_debuginfo_type_name(cx, vec_type, true);
 
     let member_llvm_types = slice_llvm_type.field_types();
     assert!(slice_layout_is_correct(cx,
@@ -2845,7 +2811,7 @@ fn vec_slice_metadata(cx: &CrateContext,
                                            slice_type_name.as_slice(),
                                            unique_type_id,
                                            member_descriptions,
-                                           file_metadata,
+                                           UNKNOWN_SCOPE_METADATA,
                                            file_metadata,
                                            span);
     return MetadataCreationResult::new(metadata, false);
@@ -2865,8 +2831,6 @@ fn subroutine_type_metadata(cx: &CrateContext,
                             signature: &ty::FnSig,
                             span: Span)
                          -> MetadataCreationResult {
-    let loc = span_start(cx, span);
-    let file_metadata = file_metadata(cx, loc.file.name.as_slice());
     let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
 
     // return type
@@ -2880,57 +2844,64 @@ fn subroutine_type_metadata(cx: &CrateContext,
         signature_metadata.push(type_metadata(cx, argument_type, span));
     }
 
-    match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-        Some(metadata) => return MetadataCreationResult::new(metadata, true),
-        None => { /* proceed */ }
-    };
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
     return MetadataCreationResult::new(
         unsafe {
             llvm::LLVMDIBuilderCreateSubroutineType(
                 DIB(cx),
-                file_metadata,
+                UNKNOWN_FILE_METADATA,
                 create_DIArray(DIB(cx), signature_metadata.as_slice()))
         },
         false);
 }
 
-fn trait_metadata(cx: &CrateContext,
-                  def_id: ast::DefId,
-                  trait_type: ty::t,
-                  substs: &subst::Substs,
-                  trait_store: ty::TraitStore,
-                  _: &ty::BuiltinBounds,
-                  unique_type_id: UniqueTypeId)
-               -> DIType {
+fn trait_pointer_metadata(cx: &CrateContext,
+                          // trait_pointer_type must be the type of the fat
+                          // pointer to the concrete trait object
+                          trait_pointer_type: ty::t,
+                          unique_type_id: UniqueTypeId)
+                       -> DIType {
     // The implementation provided here is a stub. It makes sure that the trait
     // type is assigned the correct name, size, namespace, and source location.
     // But it does not describe the trait's methods.
-    let last = ty::with_path(cx.tcx(), def_id, |mut path| path.last().unwrap());
-    let ident_string = token::get_name(last.name());
-    let mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store);
-    name.push_str(ident_string.get());
 
-    // Add type and region parameters
-    let trait_def = ty::lookup_trait_def(cx.tcx(), def_id);
-    let name = ppaux::parameterized(cx.tcx(), name.as_slice(),
-                                    substs, &trait_def.generics);
+    let trait_object_type = match ty::get(trait_pointer_type).sty {
+        ty::ty_uniq(pointee_type) => pointee_type,
+        ty::ty_rptr(_, ty::mt { ty, .. }) => ty,
+        _ => {
+            let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_pointer_type);
+            cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \
+                                   trait_pointer_metadata(): {}",
+                                   pp_type_name.as_slice()).as_slice());
+        }
+    };
+
+    let def_id = match ty::get(trait_object_type).sty {
+        ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id,
+        _ => {
+            let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_object_type);
+            cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
+                                   trait_pointer_metadata(): {}",
+                                   pp_type_name.as_slice()).as_slice());
+        }
+    };
 
-    let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);
+    let trait_pointer_type_name =
+        compute_debuginfo_type_name(cx, trait_pointer_type, false);
 
-    let file_name = span_start(cx, definition_span).file.name.clone();
-    let file_metadata = file_metadata(cx, file_name.as_slice());
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
 
-    let trait_llvm_type = type_of::type_of(cx, trait_type);
+    let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type);
 
     composite_type_metadata(cx,
-                            trait_llvm_type,
-                            name.as_slice(),
+                            trait_pointer_llvm_type,
+                            trait_pointer_type_name.as_slice(),
                             unique_type_id,
                             [],
                             containing_scope,
-                            file_metadata,
-                            definition_span)
+                            UNKNOWN_FILE_METADATA,
+                            codemap::DUMMY_SP)
 }
 
 fn type_metadata(cx: &CrateContext,
@@ -2972,15 +2943,6 @@ fn type_metadata(cx: &CrateContext,
 
     debug!("type_metadata: {:?}", ty::get(t));
 
-    macro_rules! return_if_created_in_meantime(
-        () => (
-            match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
-                Some(metadata) => return metadata,
-                None => { /* proceed normally */ }
-            };
-        )
-    )
-
     let sty = &ty::get(t).sty;
     let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
         ty::ty_nil      |
@@ -3010,19 +2972,22 @@ macro_rules! return_if_created_in_meantime(
                     let i8_t = ty::mk_i8();
                     heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
                 }
-                ty::ty_trait(box ty::TyTrait {
-                        def_id,
-                        ref substs,
-                        ref bounds
-                    }) => {
+                ty::ty_trait(..) => {
                     MetadataCreationResult::new(
-                        trait_metadata(cx, def_id, t, substs, ty::UniqTraitStore,
-                                       bounds, unique_type_id),
-                    false)
+                        trait_pointer_metadata(cx, t, unique_type_id),
+                        false)
                 }
                 _ => {
-                    let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
-                    return_if_created_in_meantime!();
+                    let pointee_metadata = type_metadata(cx,
+                                                         pointee_type,
+                                                         usage_site_span);
+                    match debug_context(cx).type_map
+                                           .borrow()
+                                           .find_metadata_for_unique_id(unique_type_id) {
+                        Some(metadata) => return metadata,
+                        None => { /* proceed normally */ }
+                    };
+
                     MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata),
                                                 false)
                 }
@@ -3034,22 +2999,23 @@ macro_rules! return_if_created_in_meantime(
                     vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
                 }
                 ty::ty_str => {
-                    vec_slice_metadata(cx, t, ty::mk_i8(), unique_type_id, usage_site_span)
+                    vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
                 }
-                ty::ty_trait(box ty::TyTrait {
-                        def_id,
-                        ref substs,
-                        ref bounds
-                    }) => {
+                ty::ty_trait(..) => {
                     MetadataCreationResult::new(
-                        trait_metadata(cx, def_id, t, substs,
-                                       ty::RegionTraitStore(ty::ReStatic, mt.mutbl),
-                                       bounds, unique_type_id),
-                    false)
+                        trait_pointer_metadata(cx, t, unique_type_id),
+                        false)
                 }
                 _ => {
                     let pointee = type_metadata(cx, mt.ty, usage_site_span);
-                    return_if_created_in_meantime!();
+
+                    match debug_context(cx).type_map
+                                           .borrow()
+                                           .find_metadata_for_unique_id(unique_type_id) {
+                        Some(metadata) => return metadata,
+                        None => { /* proceed normally */ }
+                    };
+
                     MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false)
                 }
             }
@@ -3167,7 +3133,8 @@ fn set_debug_location(cx: &CrateContext, debug_location: DebugLocation) {
 
     match debug_location {
         KnownLocation { scope, line, .. } => {
-            let col = 0u; // Always set the column to zero like Clang and GCC
+            // Always set the column to zero like Clang and GCC
+            let col = UNKNOWN_COLUMN_NUMBER;
             debug!("setting debug location to {} {}", line, col);
             let elements = [C_i32(cx, line as i32), C_i32(cx, col as i32),
                             scope, ptr::mut_null()];
@@ -3717,6 +3684,265 @@ fn walk_expr(cx: &CrateContext,
 }
 
 
+//=-----------------------------------------------------------------------------
+// Type Names for Debug Info
+//=-----------------------------------------------------------------------------
+
+// Compute the name of the type as it should be stored in debuginfo. Does not do
+// any caching, i.e. calling the function twice with the same type will also do
+// the work twice. The `qualified` parameter only affects the first level of the
+// type name, further levels (i.e. type parameters) are always fully qualified.
+fn compute_debuginfo_type_name(cx: &CrateContext,
+                               t: ty::t,
+                               qualified: bool)
+                            -> String {
+    let mut result = String::with_capacity(64);
+    push_debuginfo_type_name(cx, t, qualified, &mut result);
+    result
+}
+
+// Pushes the name of the type as it should be stored in debuginfo on the
+// `output` String. See also compute_debuginfo_type_name().
+fn push_debuginfo_type_name(cx: &CrateContext,
+                            t: ty::t,
+                            qualified: bool,
+                            output:&mut String) {
+    match ty::get(t).sty {
+        ty::ty_nil               => output.push_str("()"),
+        ty::ty_bot               => output.push_str("!"),
+        ty::ty_bool              => output.push_str("bool"),
+        ty::ty_char              => output.push_str("char"),
+        ty::ty_str               => output.push_str("str"),
+        ty::ty_int(ast::TyI)     => output.push_str("int"),
+        ty::ty_int(ast::TyI8)    => output.push_str("i8"),
+        ty::ty_int(ast::TyI16)   => output.push_str("i16"),
+        ty::ty_int(ast::TyI32)   => output.push_str("i32"),
+        ty::ty_int(ast::TyI64)   => output.push_str("i64"),
+        ty::ty_uint(ast::TyU)    => output.push_str("uint"),
+        ty::ty_uint(ast::TyU8)   => output.push_str("u8"),
+        ty::ty_uint(ast::TyU16)  => output.push_str("u16"),
+        ty::ty_uint(ast::TyU32)  => output.push_str("u32"),
+        ty::ty_uint(ast::TyU64)  => output.push_str("u64"),
+        ty::ty_float(ast::TyF32) => output.push_str("f32"),
+        ty::ty_float(ast::TyF64) => output.push_str("f64"),
+        ty::ty_struct(def_id, ref substs) |
+        ty::ty_enum(def_id, ref substs) => {
+            push_item_name(cx, def_id, qualified, output);
+            push_type_params(cx, substs, output);
+        },
+        ty::ty_tup(ref component_types) => {
+            output.push_char('(');
+            for &component_type in component_types.iter() {
+                push_debuginfo_type_name(cx, component_type, true, output);
+                output.push_str(", ");
+            }
+            output.pop_char();
+            output.pop_char();
+            output.push_char(')');
+        },
+        ty::ty_uniq(inner_type) => {
+            output.push_str("Box<");
+            push_debuginfo_type_name(cx, inner_type, true, output);
+            output.push_char('>');
+        },
+        ty::ty_box(inner_type) => {
+            output.push_char('@');
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+            output.push_char('*');
+            match mutbl {
+                ast::MutImmutable => output.push_str("const "),
+                ast::MutMutable => output.push_str("mut "),
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+            output.push_char('&');
+            if mutbl == ast::MutMutable {
+                output.push_str("mut ");
+            }
+
+            push_debuginfo_type_name(cx, inner_type, true, output);
+        },
+        ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
+            output.push_char('[');
+            push_debuginfo_type_name(cx, inner_type, true, output);
+
+            match optional_length {
+                Some(len) => {
+                    output.push_str(format!(", ..{}", len).as_slice());
+                }
+                None => { /* nothing to do */ }
+            };
+
+            output.push_char(']');
+        },
+        ty::ty_trait(ref trait_data) => {
+            push_item_name(cx, trait_data.def_id, false, output);
+            push_type_params(cx, &trait_data.substs, output);
+        },
+        ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
+            if fn_style == ast::UnsafeFn {
+                output.push_str("unsafe ");
+            }
+
+            if abi != ::syntax::abi::Rust {
+                output.push_str("extern \"");
+                output.push_str(abi.name());
+                output.push_str("\" ");
+            }
+
+            output.push_str("fn(");
+
+            if sig.inputs.len() > 0 {
+                for &parameter_type in sig.inputs.iter() {
+                    push_debuginfo_type_name(cx, parameter_type, true, output);
+                    output.push_str(", ");
+                }
+                output.pop_char();
+                output.pop_char();
+            }
+
+            if sig.variadic {
+                if sig.inputs.len() > 0 {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push_char(')');
+
+            if !ty::type_is_nil(sig.output) {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output, true, output);
+            }
+        },
+        ty::ty_closure(box ty::ClosureTy { fn_style,
+                                           onceness,
+                                           store,
+                                           ref sig,
+                                           .. // omitting bounds ...
+                                           }) => {
+            if fn_style == ast::UnsafeFn {
+                output.push_str("unsafe ");
+            }
+
+            if onceness == ast::Once {
+                output.push_str("once ");
+            }
+
+            let param_list_closing_char;
+            match store {
+                ty::UniqTraitStore => {
+                    output.push_str("proc(");
+                    param_list_closing_char = ')';
+                }
+                ty::RegionTraitStore(_, ast::MutMutable) => {
+                    output.push_str("&mut|");
+                    param_list_closing_char = '|';
+                }
+                ty::RegionTraitStore(_, ast::MutImmutable) => {
+                    output.push_str("&|");
+                    param_list_closing_char = '|';
+                }
+            };
+
+            if sig.inputs.len() > 0 {
+                for &parameter_type in sig.inputs.iter() {
+                    push_debuginfo_type_name(cx, parameter_type, true, output);
+                    output.push_str(", ");
+                }
+                output.pop_char();
+                output.pop_char();
+            }
+
+            if sig.variadic {
+                if sig.inputs.len() > 0 {
+                    output.push_str(", ...");
+                } else {
+                    output.push_str("...");
+                }
+            }
+
+            output.push_char(param_list_closing_char);
+
+            if !ty::type_is_nil(sig.output) {
+                output.push_str(" -> ");
+                push_debuginfo_type_name(cx, sig.output, true, output);
+            }
+        },
+        ty::ty_err      |
+        ty::ty_infer(_) |
+        ty::ty_param(_) => {
+            cx.sess().bug(format!("debuginfo: Trying to create type name for \
+                unexpected type: {}", ppaux::ty_to_str(cx.tcx(), t)).as_slice());
+        }
+    }
+
+    fn push_item_name(cx: &CrateContext,
+                      def_id: ast::DefId,
+                      qualified: bool,
+                      output: &mut String) {
+        ty::with_path(cx.tcx(), def_id, |mut path| {
+            if qualified {
+                if def_id.krate == ast::LOCAL_CRATE {
+                    output.push_str(crate_root_namespace(cx));
+                    output.push_str("::");
+                }
+
+                let mut path_element_count = 0u;
+                for path_element in path {
+                    let name = token::get_name(path_element.name());
+                    output.push_str(name.get());
+                    output.push_str("::");
+                    path_element_count += 1;
+                }
+
+                if path_element_count == 0 {
+                    cx.sess().bug("debuginfo: Encountered empty item path!");
+                }
+
+                output.pop_char();
+                output.pop_char();
+            } else {
+                let name = token::get_name(path.last()
+                                               .expect("debuginfo: Empty item path?")
+                                               .name());
+                output.push_str(name.get());
+            }
+        });
+    }
+
+    // Pushes the type parameters in the given `Substs` to the output string.
+    // This ignores region parameters, since they can't reliably be
+    // reconstructed for items from non-local crates. For local crates, this
+    // would be possible but with inlining and LTO we have to use the least
+    // common denominator - otherwise we would run into conflicts.
+    fn push_type_params(cx: &CrateContext,
+                        substs: &subst::Substs,
+                        output: &mut String) {
+        if substs.types.is_empty() {
+            return;
+        }
+
+        output.push_char('<');
+
+        for &type_parameter in substs.types.iter() {
+            push_debuginfo_type_name(cx, type_parameter, true, output);
+            output.push_str(", ");
+        }
+
+        output.pop_char();
+        output.pop_char();
+
+        output.push_char('>');
+    }
+}
+
+
 //=-----------------------------------------------------------------------------
 // Namespace Handling
 //=-----------------------------------------------------------------------------
@@ -3748,14 +3974,15 @@ fn fill_nested(node: &NamespaceTreeNode, output: &mut String) {
     }
 }
 
+fn crate_root_namespace<'a>(cx: &'a CrateContext) -> &'a str {
+    cx.link_meta.crateid.name.as_slice()
+}
+
 fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTreeNode> {
     ty::with_path(cx.tcx(), def_id, |path| {
         // prepend crate name if not already present
         let krate = if def_id.krate == ast::LOCAL_CRATE {
-            let crate_namespace_ident = token::str_to_ident(cx.link_meta
-                                                              .crateid
-                                                              .name
-                                                              .as_slice());
+            let crate_namespace_ident = token::str_to_ident(crate_root_namespace(cx));
             Some(ast_map::PathMod(crate_namespace_ident.name))
         } else {
             None
diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs
new file mode 100644 (file)
index 0000000..ac5fe83
--- /dev/null
@@ -0,0 +1,333 @@
+// Copyright 2013-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.
+
+// ignore-tidy-linelength
+// ignore-lldb
+// ignore-android: FIXME(#10381)
+
+// compile-flags:-g
+// gdb-command:rbreak zzz
+// gdb-command:run
+// gdb-command:finish
+
+
+// STRUCTS
+// gdb-command:whatis simple_struct
+// gdb-check:type = struct Struct1
+
+// gdb-command:whatis generic_struct1
+// gdb-check:type = struct GenericStruct<type-names::Mod1::Struct2, type-names::Mod1::Mod2::Struct3>
+
+// gdb-command:whatis generic_struct2
+// gdb-check:type = struct GenericStruct<type-names::Struct1, extern "fastcall" fn(int) -> uint>
+
+// gdb-command:whatis mod_struct
+// gdb-check:type = struct Struct2
+
+
+// ENUMS
+// gdb-command:whatis simple_enum_1
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_2
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_3
+// gdb-check:type = union Enum2
+
+// gdb-command:whatis generic_enum_1
+// gdb-check:type = union Enum3<type-names::Mod1::Struct2>
+
+// gdb-command:whatis generic_enum_2
+// gdb-check:type = union Enum3<type-names::Struct1>
+
+
+// TUPLES
+// gdb-command:whatis tuple1
+// gdb-check:type = struct (u32, type-names::Struct1, type-names::Mod1::Mod2::Enum3<type-names::Mod1::Struct2>)
+
+// gdb-command:whatis tuple2
+// gdb-check:type = struct ((type-names::Struct1, type-names::Mod1::Mod2::Struct3), type-names::Mod1::Enum2, char)
+
+
+// BOX
+// gdb-command:whatis box1
+// gdb-check:type = struct (Box<f32>, i32)
+
+// gdb-command:whatis box2
+// gdb-check:type = struct (Box<type-names::Mod1::Mod2::Enum3<f32>>, i32)
+
+
+// REFERENCES
+// gdb-command:whatis ref1
+// gdb-check:type = struct (&type-names::Struct1, i32)
+
+// gdb-command:whatis ref2
+// gdb-check:type = struct (&type-names::GenericStruct<char, type-names::Struct1>, i32)
+
+// gdb-command:whatis mut_ref1
+// gdb-check:type = struct (&mut type-names::Struct1, i32)
+
+// gdb-command:whatis mut_ref2
+// gdb-check:type = struct (&mut type-names::GenericStruct<type-names::Mod1::Enum2, f64>, i32)
+
+
+// RAW POINTERS
+// gdb-command:whatis mut_ptr1
+// gdb-check:type = struct (*mut type-names::Struct1, int)
+
+// gdb-command:whatis mut_ptr2
+// gdb-check:type = struct (*mut int, int)
+
+// gdb-command:whatis mut_ptr3
+// gdb-check:type = struct (*mut type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+// gdb-command:whatis const_ptr1
+// gdb-check:type = struct (*const type-names::Struct1, int)
+
+// gdb-command:whatis const_ptr2
+// gdb-check:type = struct (*const int, int)
+
+// gdb-command:whatis const_ptr3
+// gdb-check:type = struct (*const type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+
+// VECTORS
+// gdb-command:whatis fixed_size_vec1
+// gdb-check:type = struct ([type-names::Struct1, ..3], i16)
+
+// gdb-command:whatis fixed_size_vec2
+// gdb-check:type = struct ([uint, ..3], i16)
+
+// gdb-command:whatis slice1
+// gdb-check:type = struct &[uint]
+
+// gdb-command:whatis slice2
+// gdb-check:type = struct &[type-names::Mod1::Enum2]
+
+
+// TRAITS
+// gdb-command:whatis box_trait
+// gdb-check:type = struct Box<Trait1>
+
+// gdb-command:whatis ref_trait
+// gdb-check:type = struct &Trait1
+
+// gdb-command:whatis mut_ref_trait
+// gdb-check:type = struct &mut Trait1
+
+// gdb-command:whatis generic_box_trait
+// gdb-check:type = struct Box<Trait2<i32, type-names::Mod1::Struct2>>
+
+// gdb-command:whatis generic_ref_trait
+// gdb-check:type = struct &Trait2<type-names::Struct1, type-names::Struct1>
+
+// gdb-command:whatis generic_mut_ref_trait
+// gdb-check:type = struct &mut Trait2<type-names::Mod1::Mod2::Struct3, type-names::GenericStruct<uint, int>>
+
+
+// BARE FUNCTIONS
+// gdb-command:whatis rust_fn
+// gdb-check:type = struct (fn(core::option::Option<int>, core::option::Option<&type-names::Mod1::Struct2>), uint)
+
+// gdb-command:whatis extern_c_fn
+// gdb-check:type = struct (extern "C" fn(int), uint)
+
+// gdb-command:whatis unsafe_fn
+// gdb-check:type = struct (unsafe fn(core::result::Result<char, f64>), uint)
+
+// gdb-command:whatis extern_stdcall_fn
+// gdb-check:type = struct (extern "stdcall" fn(), uint)
+
+// gdb-command:whatis rust_fn_with_return_value
+// gdb-check:type = struct (fn(f64) -> uint, uint)
+
+// gdb-command:whatis extern_c_fn_with_return_value
+// gdb-check:type = struct (extern "C" fn() -> type-names::Struct1, uint)
+
+// gdb-command:whatis unsafe_fn_with_return_value
+// gdb-check:type = struct (unsafe fn(type-names::GenericStruct<u16, u8>) -> type-names::Mod1::Struct2, uint)
+
+// gdb-command:whatis extern_stdcall_fn_with_return_value
+// gdb-check:type = struct (extern "stdcall" fn(Box<int>) -> uint, uint)
+
+// gdb-command:whatis generic_function_int
+// gdb-check:type = struct (fn(int) -> int, uint)
+
+// gdb-command:whatis generic_function_struct3
+// gdb-check:type = struct (fn(type-names::Mod1::Mod2::Struct3) -> type-names::Mod1::Mod2::Struct3, uint)
+
+// gdb-command:whatis variadic_function
+// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> int, uint)
+
+
+// CLOSURES
+// gdb-command:whatis some_proc
+// gdb-check:type = struct (once proc(int, u8) -> (int, u8), uint)
+
+// gdb-command:whatis stack_closure1
+// gdb-check:type = struct (&mut|int|, uint)
+
+// gdb-command:whatis stack_closure2
+// gdb-check:type = struct (&mut|i8, f32| -> f32, uint)
+
+use std::ptr;
+
+struct Struct1;
+struct GenericStruct<T1, T2>;
+
+enum Enum1 {
+    Variant1_1,
+    Variant1_2(int)
+}
+
+mod Mod1 {
+    pub struct Struct2;
+
+    pub enum Enum2 {
+        Variant2_1,
+        Variant2_2(super::Struct1)
+    }
+
+    pub mod Mod2 {
+        pub struct Struct3;
+
+        pub enum Enum3<T> {
+            Variant3_1,
+            Variant3_2(T),
+        }
+    }
+}
+
+trait Trait1 { }
+trait Trait2<T1, T2> { }
+
+impl Trait1 for int {}
+impl<T1, T2> Trait2<T1, T2> for int {}
+
+fn rust_fn(_: Option<int>, _: Option<&Mod1::Struct2>) {}
+extern "C" fn extern_c_fn(_: int) {}
+unsafe fn unsafe_fn(_: Result<char, f64>) {}
+extern "stdcall" fn extern_stdcall_fn() {}
+
+fn rust_fn_with_return_value(_: f64) -> uint { 4 }
+extern "C" fn extern_c_fn_with_return_value() -> Struct1 { Struct1 }
+unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> Mod1::Struct2 { Mod1::Struct2 }
+extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box<int>) -> uint { 0 }
+
+fn generic_function<T>(x: T) -> T { x }
+
+extern {
+    fn printf(_:*const u8, ...) -> int;
+}
+
+// In many of the cases below, the type that is actually under test is wrapped
+// in a tuple, e.g. Box<T>, references, raw pointers, fixed-size vectors, ...
+// This is because GDB will not print the type name from DWARF debuginfo for
+// some kinds of types (pointers, arrays, functions, ...)
+// Since tuples are structs as far as GDB is concerned, their name will be
+// printed correctly, so the tests below just construct a tuple type that will
+// then *contain* the type name that we want to see.
+fn main() {
+
+    // Structs
+    let simple_struct = Struct1;
+    let generic_struct1: GenericStruct<Mod1::Struct2, Mod1::Mod2::Struct3> = GenericStruct;
+    let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(int) -> uint> = GenericStruct;
+    let mod_struct = Mod1::Struct2;
+
+    // Enums
+    let simple_enum_1 = Variant1_1;
+    let simple_enum_2 = Variant1_2(0);
+    let simple_enum_3 = Mod1::Variant2_2(Struct1);
+
+    let generic_enum_1: Mod1::Mod2::Enum3<Mod1::Struct2> = Mod1::Mod2::Variant3_1;
+    let generic_enum_2 = Mod1::Mod2::Variant3_2(Struct1);
+
+    // Tuples
+    let tuple1 = (8u32, Struct1, Mod1::Mod2::Variant3_2(Mod1::Struct2));
+    let tuple2 = ((Struct1, Mod1::Mod2::Struct3), Mod1::Variant2_1, 'x');
+
+    // Box
+    let box1 = (box 1f32, 0i32);
+    let box2 = (box Mod1::Mod2::Variant3_2(1f32), 0i32);
+
+    // References
+    let ref1 = (&Struct1, 0i32);
+    let ref2 = (&GenericStruct::<char, Struct1>, 0i32);
+
+    let mut mut_struct1 = Struct1;
+    let mut mut_generic_struct = GenericStruct::<Mod1::Enum2, f64>;
+    let mut_ref1 = (&mut mut_struct1, 0i32);
+    let mut_ref2 = (&mut mut_generic_struct, 0i32);
+
+    // Raw Pointers
+    let mut_ptr1: (*mut Struct1, int) = (ptr::mut_null(), 0);
+    let mut_ptr2: (*mut int, int) = (ptr::mut_null(), 0);
+    let mut_ptr3: (*mut Mod1::Mod2::Enum3<Struct1>, int) = (ptr::mut_null(), 0);
+
+    let const_ptr1: (*const Struct1, int) = (ptr::null(), 0);
+    let const_ptr2: (*const int, int) = (ptr::null(), 0);
+    let const_ptr3: (*const Mod1::Mod2::Enum3<Struct1>, int) = (ptr::null(), 0);
+
+    // Vectors
+    let fixed_size_vec1 = ([Struct1, Struct1, Struct1], 0i16);
+    let fixed_size_vec2 = ([0u, 1u, 2u], 0i16);
+
+    let vec1 = vec![0u, 2u, 3u];
+    let slice1 = vec1.as_slice();
+    let vec2 = vec![Mod1::Variant2_2(Struct1)];
+    let slice2 = vec2.as_slice();
+
+    // Trait Objects
+    let box_trait = (box 0i) as Box<Trait1>;
+    let ref_trait = &0i as &Trait1;
+    let mut mut_int1 = 0i;
+    let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
+
+    let generic_box_trait = (box 0i) as Box<Trait2<i32, Mod1::Struct2>>;
+    let generic_ref_trait  = (&0i) as &Trait2<Struct1, Struct1>;
+
+    let mut generic_mut_ref_trait_impl = 0i;
+    let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
+        &mut Trait2<Mod1::Mod2::Struct3, GenericStruct<uint, int>>;
+
+    // Bare Functions
+    let rust_fn = (rust_fn, 0u);
+    let extern_c_fn = (extern_c_fn, 0u);
+    let unsafe_fn = (unsafe_fn, 0u);
+    let extern_stdcall_fn = (extern_stdcall_fn, 0u);
+
+    let rust_fn_with_return_value = (rust_fn_with_return_value, 0u);
+    let extern_c_fn_with_return_value = (extern_c_fn_with_return_value, 0u);
+    let unsafe_fn_with_return_value = (unsafe_fn_with_return_value, 0u);
+    let extern_stdcall_fn_with_return_value = (extern_stdcall_fn_with_return_value, 0u);
+
+    let generic_function_int = (generic_function::<int>, 0u);
+    let generic_function_struct3 = (generic_function::<Mod1::Mod2::Struct3>, 0u);
+
+    let variadic_function = (printf, 0u);
+
+    // Closures
+    // I (mw) am a bit unclear about the current state of closures, their
+    // various forms (boxed, unboxed, proc, capture-by-ref, by-val, once) and
+    // how that maps to rustc's internal representation of these forms.
+    // Once closures have reached their 1.0 form, the tests below should
+    // probably be expanded.
+    let some_proc = (proc(a:int, b:u8) (a, b), 0u);
+
+    let stack_closure1 = (|x:int| {}, 0u);
+    let stack_closure2 = (|x:i8, y: f32| { (x as f32) + y }, 0u);
+
+    zzz();
+}
+
+#[inline(never)]
+fn zzz() { () }