* `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.
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() {}
~~~
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
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="$@"
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 ]
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}" ]
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]
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]
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]
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 {
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`.
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};
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]
}
}
-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,
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
}
///
/// 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,
/// 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())),
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>>> {
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
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
// 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))
}
_ => 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
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) => {
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()");
}).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>,
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(),
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 {
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
}
})
}
// <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,
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()),
}
}
_ => 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
})
}
// 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)));
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
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
}
})
}
#[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>(
}
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 {
},
_ => 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"),
}
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
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(_, _) => {
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;
}
}
}
}
- 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}) => {
// 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);
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();
}
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 {
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,
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
//=-----------------------------------------------------------------------------
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 ");
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));
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));
}
}
+// 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 {
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(",");
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 {
-> 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(
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory,
},
FinalMetadata(DICompositeType)
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory)
-> RecursiveTypeDescription {
unique_type_id: unique_type_id,
metadata_stub: metadata_stub,
llvm_type: llvm_type,
- file_metadata: file_metadata,
member_description_factory: member_description_factory,
}
}
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
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);
}
}
}
}
+
fn prepare_struct_metadata(cx: &CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
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);
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),
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,
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,
&**self.variants.get(i),
discriminant_info,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions = member_desc_factory
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,
&**self.variants.get(0),
NoDiscriminant,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions =
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(),
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
self.containing_scope,
- self.file_metadata,
self.span);
let variant_member_descriptions =
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.
variant_info: &ty::VariantInfo,
discriminant_info: EnumDiscriminantInfo,
containing_scope: DIScope,
- file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, MemberDescriptionFactory) {
let variant_llvm_type =
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
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 {
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);
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()),
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
unique_type_id,
enum_metadata,
enum_llvm_type,
- file_metadata,
EnumMDF(EnumMemberDescriptionFactory {
enum_type: enum_type,
type_rep: type_rep.clone(),
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;
}
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().
}
}
- let loc = span_start(cx, definition_span);
-
let member_metadata: Vec<DIDescriptor> = member_descriptions
.iter()
.enumerate()
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),
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
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,
-> 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);
let nil_pointer_type_metadata = type_metadata(cx,
nil_pointer_type,
codemap::DUMMY_SP);
-
let member_descriptions = [
MemberDescription {
name: "refcnt".to_string(),
}
];
- 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);
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,
-> 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);
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();
vec_pointer_type_name,
vec_box_unique_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
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,
slice_type_name.as_slice(),
unique_type_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
return MetadataCreationResult::new(metadata, false);
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
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,
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 |
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)
}
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)
}
}
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()];
}
+//=-----------------------------------------------------------------------------
+// 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 ¶meter_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 ¶meter_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
//=-----------------------------------------------------------------------------
}
}
+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
--- /dev/null
+// 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() { () }