Auto merge of #21970 - michaelwoerister:lang-item-call-debug-locs, r=brson

Resolves some issues caused by the recent LLVM update (which itself solved some issues).

Closes #19848
Closes #20798
This commit is contained in:
bors 2015-02-08 10:27:58 +00:00
commit d4a66e9b09
16 changed files with 499 additions and 201 deletions

View File

@ -28,7 +28,7 @@ use std::iter::{range_inclusive, AdditiveIterator, FromIterator, repeat};
use std::num::Float;
use std::slice;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId, Pat};
use syntax::ast_util::walk_pat;
use syntax::ast_util;
use syntax::codemap::{Span, Spanned, DUMMY_SP};
use syntax::fold::{Folder, noop_fold_pat};
use syntax::print::pprust::pat_to_string;
@ -36,6 +36,7 @@ use syntax::parse::token;
use syntax::ptr::P;
use syntax::visit::{self, Visitor, FnKind};
use util::ppaux::ty_to_string;
use util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
id: DUMMY_NODE_ID,
@ -171,7 +172,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) {
}
}
let mut static_inliner = StaticInliner::new(cx.tcx);
let mut static_inliner = StaticInliner::new(cx.tcx, None);
let inlined_arms = arms.iter().map(|arm| {
(arm.pats.iter().map(|pat| {
static_inliner.fold_pat((*pat).clone())
@ -235,7 +236,7 @@ fn is_expr_const_nan(tcx: &ty::ctxt, expr: &ast::Expr) -> bool {
}
fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) {
walk_pat(pat, |p| {
ast_util::walk_pat(pat, |p| {
match p.node {
ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => {
let pat_ty = ty::pat_ty(cx.tcx, p);
@ -266,7 +267,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat)
// Check that we do not match against a static NaN (#6804)
fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
walk_pat(pat, |p| {
ast_util::walk_pat(pat, |p| {
match p.node {
ast::PatLit(ref expr) if is_expr_const_nan(cx.tcx, &**expr) => {
span_warn!(cx.tcx.sess, p.span, E0003,
@ -399,28 +400,50 @@ fn const_val_to_expr(value: &const_val) -> P<ast::Expr> {
pub struct StaticInliner<'a, 'tcx: 'a> {
pub tcx: &'a ty::ctxt<'tcx>,
pub failed: bool
pub failed: bool,
pub renaming_map: Option<&'a mut FnvHashMap<(NodeId, Span), NodeId>>,
}
impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
pub fn new<'b>(tcx: &'b ty::ctxt<'tcx>) -> StaticInliner<'b, 'tcx> {
pub fn new<'b>(tcx: &'b ty::ctxt<'tcx>,
renaming_map: Option<&'b mut FnvHashMap<(NodeId, Span), NodeId>>)
-> StaticInliner<'b, 'tcx> {
StaticInliner {
tcx: tcx,
failed: false
failed: false,
renaming_map: renaming_map
}
}
}
struct RenamingRecorder<'map> {
substituted_node_id: NodeId,
origin_span: Span,
renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId>
}
impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> {
fn visit_id(&mut self, node_id: NodeId) {
let key = (node_id, self.origin_span);
self.renaming_map.insert(key, self.substituted_node_id);
}
}
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
match pat.node {
return match pat.node {
ast::PatIdent(..) | ast::PatEnum(..) => {
let def = self.tcx.def_map.borrow().get(&pat.id).cloned();
match def {
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr).map(|mut new_pat| {
new_pat.span = pat.span;
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
if let Some(ref mut renaming_map) = self.renaming_map {
// Record any renamings we do here
record_renamings(const_expr, &pat, renaming_map);
}
new_pat
})
}
@ -435,6 +458,24 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
}
}
_ => noop_fold_pat(pat, self)
};
fn record_renamings(const_expr: &ast::Expr,
substituted_pat: &ast::Pat,
renaming_map: &mut FnvHashMap<(NodeId, Span), NodeId>) {
let mut renaming_recorder = RenamingRecorder {
substituted_node_id: substituted_pat.id,
origin_span: substituted_pat.span,
renaming_map: renaming_map,
};
let mut id_visitor = ast_util::IdVisitor {
operation: &mut renaming_recorder,
pass_through_items: true,
visited_outermost: false,
};
id_visitor.visit_expr(const_expr);
}
}
}
@ -953,7 +994,7 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &ast::Local) {
ast::LocalFor => "`for` loop"
};
let mut static_inliner = StaticInliner::new(cx.tcx);
let mut static_inliner = StaticInliner::new(cx.tcx, None);
is_refutable(cx, &*static_inliner.fold_pat(loc.pat.clone()), |pat| {
span_err!(cx.tcx.sess, loc.pat.span, E0005,
"refutable pattern in {} binding: `{}` not covered",
@ -1040,7 +1081,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt,
};
for pat in pats {
walk_pat(&**pat, |p| {
ast_util::walk_pat(&**pat, |p| {
if pat_is_binding(def_map, &*p) {
match p.node {
ast::PatIdent(ast::BindByValue(_), _, ref sub) => {

View File

@ -22,6 +22,7 @@ use middle::astconv_util::{ast_ty_to_prim_ty};
use util::nodemap::DefIdMap;
use syntax::ast::{self, Expr};
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::visit::{self, Visitor};
@ -304,10 +305,10 @@ pub enum const_val {
const_bool(bool)
}
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
let pat = match expr.node {
ast::ExprTup(ref exprs) =>
ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr)).collect()),
ast::PatTup(exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect()),
ast::ExprCall(ref callee, ref args) => {
let def = tcx.def_map.borrow()[callee.id].clone();
@ -319,7 +320,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
def::DefVariant(_, variant_did, _) => def_to_path(tcx, variant_did),
_ => unreachable!()
};
let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &**expr)).collect();
let pats = args.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect();
ast::PatEnum(path, Some(pats))
}
@ -328,7 +329,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
span: codemap::DUMMY_SP,
node: ast::FieldPat {
ident: field.ident.node,
pat: const_expr_to_pat(tcx, &*field.expr),
pat: const_expr_to_pat(tcx, &*field.expr, span),
is_shorthand: false,
},
}).collect();
@ -336,7 +337,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
}
ast::ExprVec(ref exprs) => {
let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr)).collect();
let pats = exprs.iter().map(|expr| const_expr_to_pat(tcx, &**expr, span)).collect();
ast::PatVec(pats, None, vec![])
}
@ -349,7 +350,7 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
ast::PatEnum(path.clone(), None),
_ => {
match lookup_const(tcx, expr) {
Some(actual) => return const_expr_to_pat(tcx, actual),
Some(actual) => return const_expr_to_pat(tcx, actual, span),
_ => unreachable!()
}
}
@ -358,14 +359,14 @@ pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr) -> P<ast::Pat> {
ast::ExprQPath(_) => {
match lookup_const(tcx, expr) {
Some(actual) => return const_expr_to_pat(tcx, actual),
Some(actual) => return const_expr_to_pat(tcx, actual, span),
_ => unreachable!()
}
}
_ => ast::PatLit(P(expr.clone()))
};
P(ast::Pat { id: expr.id, node: pat, span: expr.span })
P(ast::Pat { id: expr.id, node: pat, span: span })
}
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {

View File

@ -213,7 +213,7 @@ use trans::expr::{self, Dest};
use trans::tvec;
use trans::type_of;
use middle::ty::{self, Ty};
use session::config::FullDebugInfo;
use session::config::{NoDebugInfo, FullDebugInfo};
use util::common::indenter;
use util::nodemap::FnvHashMap;
use util::ppaux::{Repr, vec_map_to_string};
@ -222,7 +222,7 @@ use std;
use std::iter::AdditiveIterator;
use std::rc::Rc;
use syntax::ast;
use syntax::ast::{DUMMY_NODE_ID, Ident};
use syntax::ast::{DUMMY_NODE_ID, Ident, NodeId};
use syntax::codemap::Span;
use syntax::fold::Folder;
use syntax::ptr::P;
@ -244,25 +244,29 @@ impl<'a> ConstantExpr<'a> {
// An option identifying a branch (either a literal, an enum variant or a range)
#[derive(Debug)]
enum Opt<'a, 'tcx> {
ConstantValue(ConstantExpr<'a>),
ConstantRange(ConstantExpr<'a>, ConstantExpr<'a>),
Variant(ty::Disr, Rc<adt::Repr<'tcx>>, ast::DefId),
SliceLengthEqual(uint),
SliceLengthGreaterOrEqual(/* prefix length */ uint, /* suffix length */ uint),
ConstantValue(ConstantExpr<'a>, DebugLoc),
ConstantRange(ConstantExpr<'a>, ConstantExpr<'a>, DebugLoc),
Variant(ty::Disr, Rc<adt::Repr<'tcx>>, ast::DefId, DebugLoc),
SliceLengthEqual(uint, DebugLoc),
SliceLengthGreaterOrEqual(/* prefix length */ uint,
/* suffix length */ uint,
DebugLoc),
}
impl<'a, 'tcx> Opt<'a, 'tcx> {
fn eq(&self, other: &Opt<'a, 'tcx>, tcx: &ty::ctxt<'tcx>) -> bool {
match (self, other) {
(&ConstantValue(a), &ConstantValue(b)) => a.eq(b, tcx),
(&ConstantRange(a1, a2), &ConstantRange(b1, b2)) => {
(&ConstantValue(a, _), &ConstantValue(b, _)) => a.eq(b, tcx),
(&ConstantRange(a1, a2, _), &ConstantRange(b1, b2, _)) => {
a1.eq(b1, tcx) && a2.eq(b2, tcx)
}
(&Variant(a_disr, ref a_repr, a_def), &Variant(b_disr, ref b_repr, b_def)) => {
(&Variant(a_disr, ref a_repr, a_def, _),
&Variant(b_disr, ref b_repr, b_def, _)) => {
a_disr == b_disr && *a_repr == *b_repr && a_def == b_def
}
(&SliceLengthEqual(a), &SliceLengthEqual(b)) => a == b,
(&SliceLengthGreaterOrEqual(a1, a2), &SliceLengthGreaterOrEqual(b1, b2)) => {
(&SliceLengthEqual(a, _), &SliceLengthEqual(b, _)) => a == b,
(&SliceLengthGreaterOrEqual(a1, a2, _),
&SliceLengthGreaterOrEqual(b1, b2, _)) => {
a1 == b1 && a2 == b2
}
_ => false
@ -273,29 +277,39 @@ impl<'a, 'tcx> Opt<'a, 'tcx> {
let _icx = push_ctxt("match::trans_opt");
let ccx = bcx.ccx();
match *self {
ConstantValue(ConstantExpr(lit_expr)) => {
ConstantValue(ConstantExpr(lit_expr), _) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
let (llval, _) = consts::const_expr(ccx, &*lit_expr);
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
SingleResult(Result::new(bcx, lit_datum.val))
}
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2)) => {
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
let (l1, _) = consts::const_expr(ccx, &**l1);
let (l2, _) = consts::const_expr(ccx, &**l2);
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
Variant(disr_val, ref repr, _) => {
Variant(disr_val, ref repr, _, _) => {
adt::trans_case(bcx, &**repr, disr_val)
}
SliceLengthEqual(length) => {
SliceLengthEqual(length, _) => {
SingleResult(Result::new(bcx, C_uint(ccx, length)))
}
SliceLengthGreaterOrEqual(prefix, suffix) => {
SliceLengthGreaterOrEqual(prefix, suffix, _) => {
LowerBound(Result::new(bcx, C_uint(ccx, prefix + suffix)))
}
}
}
fn debug_loc(&self) -> DebugLoc {
match *self {
ConstantValue(_,debug_loc) |
ConstantRange(_, _, debug_loc) |
Variant(_, _, _, debug_loc) |
SliceLengthEqual(_, debug_loc) |
SliceLengthGreaterOrEqual(_, _, debug_loc) => debug_loc
}
}
}
#[derive(Copy, PartialEq)]
@ -352,6 +366,9 @@ struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
pats: Vec<&'p ast::Pat>,
data: &'a ArmData<'p, 'blk, 'tcx>,
bound_ptrs: Vec<(Ident, ValueRef)>,
// Thread along renamings done by the check_match::StaticInliner, so we can
// map back to original NodeIds
pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
}
impl<'a, 'p, 'blk, 'tcx> Repr<'tcx> for Match<'a, 'p, 'blk, 'tcx> {
@ -405,7 +422,8 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Match {
pats: pats,
data: &*br.data,
bound_ptrs: bound_ptrs
bound_ptrs: bound_ptrs,
pat_renaming_map: br.pat_renaming_map,
}
}).collect()
}
@ -449,7 +467,8 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
Match {
pats: pats,
data: br.data,
bound_ptrs: bound_ptrs
bound_ptrs: bound_ptrs,
pat_renaming_map: br.pat_renaming_map,
}
})
}).collect()
@ -527,18 +546,18 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
let _indenter = indenter();
let ctor = match opt {
&ConstantValue(ConstantExpr(expr)) => check_match::ConstantValue(
&ConstantValue(ConstantExpr(expr), _) => check_match::ConstantValue(
const_eval::eval_const_expr(bcx.tcx(), &*expr)
),
&ConstantRange(ConstantExpr(lo), ConstantExpr(hi)) => check_match::ConstantRange(
&ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => check_match::ConstantRange(
const_eval::eval_const_expr(bcx.tcx(), &*lo),
const_eval::eval_const_expr(bcx.tcx(), &*hi)
),
&SliceLengthEqual(n) =>
&SliceLengthEqual(n, _) =>
check_match::Slice(n),
&SliceLengthGreaterOrEqual(before, after) =>
&SliceLengthGreaterOrEqual(before, after, _) =>
check_match::SliceWithSubslice(before, after),
&Variant(_, _, def_id) =>
&Variant(_, _, def_id, _) =>
check_match::Constructor::Variant(def_id)
};
@ -556,34 +575,50 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
// needs to be conditionally matched at runtime; for example, the discriminant
// on a set of enum variants or a literal.
fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
m: &[Match<'a, 'p, 'blk, 'tcx>], col: uint)
m: &[Match<'a, 'p, 'blk, 'tcx>],
col: uint)
-> Vec<Opt<'p, 'tcx>> {
let tcx = bcx.tcx();
let mut found: Vec<Opt> = vec![];
for br in m {
let cur = br.pats[col];
let debug_loc = match br.pat_renaming_map {
Some(pat_renaming_map) => {
match pat_renaming_map.get(&(cur.id, cur.span)) {
Some(&id) => DebugLoc::At(id, cur.span),
None => DebugLoc::At(cur.id, cur.span),
}
}
None => DebugLoc::None
};
let opt = match cur.node {
ast::PatLit(ref l) => ConstantValue(ConstantExpr(&**l)),
ast::PatLit(ref l) => {
ConstantValue(ConstantExpr(&**l), debug_loc)
}
ast::PatIdent(..) | ast::PatEnum(..) | ast::PatStruct(..) => {
// This is either an enum variant or a variable binding.
let opt_def = tcx.def_map.borrow().get(&cur.id).cloned();
match opt_def {
Some(def::DefVariant(enum_id, var_id, _)) => {
let variant = ty::enum_variant_with_id(tcx, enum_id, var_id);
Variant(variant.disr_val, adt::represent_node(bcx, cur.id), var_id)
Variant(variant.disr_val,
adt::represent_node(bcx, cur.id),
var_id,
debug_loc)
}
_ => continue
}
}
ast::PatRange(ref l1, ref l2) => {
ConstantRange(ConstantExpr(&**l1), ConstantExpr(&**l2))
ConstantRange(ConstantExpr(&**l1), ConstantExpr(&**l2), debug_loc)
}
ast::PatVec(ref before, None, ref after) => {
SliceLengthEqual(before.len() + after.len())
SliceLengthEqual(before.len() + after.len(), debug_loc)
}
ast::PatVec(ref before, Some(_), ref after) => {
SliceLengthGreaterOrEqual(before.len(), after.len())
SliceLengthGreaterOrEqual(before.len(), after.len(), debug_loc)
}
_ => continue
};
@ -779,30 +814,32 @@ fn pick_column_to_specialize(def_map: &DefMap, m: &[Match]) -> Option<uint> {
fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
rhs_t: Ty<'tcx>)
rhs_t: Ty<'tcx>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
fn compare_str<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
rhs_t: Ty<'tcx>)
rhs_t: Ty<'tcx>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
let did = langcall(cx,
None,
&format!("comparison of `{}`",
cx.ty_to_string(rhs_t))[],
StrEqFnLangItem);
callee::trans_lang_call(cx, did, &[lhs, rhs], None)
callee::trans_lang_call(cx, did, &[lhs, rhs], None, debug_loc)
}
let _icx = push_ctxt("compare_values");
if ty::type_is_scalar(rhs_t) {
let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, ast::BiEq);
let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, ast::BiEq, debug_loc);
return Result::new(rs.bcx, rs.val);
}
match rhs_t.sty {
ty::ty_rptr(_, mt) => match mt.ty.sty {
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t),
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
ty::ty_vec(ty, _) => match ty.sty {
ty::ty_uint(ast::TyU8) => {
// NOTE: cast &[u8] to &str and abuse the str_eq lang item,
@ -812,7 +849,7 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ast::MutImmutable);
let lhs = BitCast(cx, lhs, type_of::type_of(cx.ccx(), t).ptr_to());
let rhs = BitCast(cx, rhs, type_of::type_of(cx.ccx(), t).ptr_to());
compare_str(cx, lhs, rhs, rhs_t)
compare_str(cx, lhs, rhs, rhs_t, debug_loc)
},
_ => cx.sess().bug("only byte strings supported in compare_values"),
},
@ -1046,7 +1083,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
debug!("test_val={}", bcx.val_to_string(test_val));
if opts.len() > 0 {
match opts[0] {
ConstantValue(_) | ConstantRange(_, _) => {
ConstantValue(..) | ConstantRange(..) => {
test_val = load_if_immediate(bcx, val, left_ty);
kind = if ty::type_is_integral(left_ty) {
Switch
@ -1054,12 +1091,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
Compare
};
}
Variant(_, ref repr, _) => {
Variant(_, ref repr, _, _) => {
let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val);
kind = the_kind;
if let Some(tval) = val_opt { test_val = tval; }
}
SliceLengthEqual(_) | SliceLengthGreaterOrEqual(_, _) => {
SliceLengthEqual(..) | SliceLengthGreaterOrEqual(..) => {
let (_, len) = tvec::get_base_and_len(bcx, val, left_ty);
test_val = len;
kind = Switch;
@ -1068,8 +1105,8 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
}
for o in &opts {
match *o {
ConstantRange(_, _) => { kind = Compare; break },
SliceLengthGreaterOrEqual(_, _) => { kind = CompareSliceLength; break },
ConstantRange(..) => { kind = Compare; break },
SliceLengthGreaterOrEqual(..) => { kind = CompareSliceLength; break },
_ => ()
}
}
@ -1095,10 +1132,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
// for the current conditional branch.
let mut branch_chk = None;
let mut opt_cx = else_cx;
let debug_loc = opt.debug_loc();
if !exhaustive || i + 1 < len {
opt_cx = bcx.fcx.new_temp_block("match_case");
match kind {
Single => Br(bcx, opt_cx.llbb, DebugLoc::None),
Single => Br(bcx, opt_cx.llbb, debug_loc),
Switch => {
match opt.trans(bcx) {
SingleResult(r) => {
@ -1121,22 +1160,33 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let Result { bcx: after_cx, val: matches } = {
match opt.trans(bcx) {
SingleResult(Result { bcx, val }) => {
compare_values(bcx, test_val, val, t)
compare_values(bcx, test_val, val, t, debug_loc)
}
RangeResult(Result { val: vbegin, .. },
Result { bcx, val: vend }) => {
let Result { bcx, val: llge } =
compare_scalar_types(
bcx, test_val,
vbegin, t, ast::BiGe);
compare_scalar_types(bcx,
test_val,
vbegin,
t,
ast::BiGe,
debug_loc);
let Result { bcx, val: llle } =
compare_scalar_types(
bcx, test_val, vend,
t, ast::BiLe);
Result::new(bcx, And(bcx, llge, llle, DebugLoc::None))
compare_scalar_types(bcx,
test_val,
vend,
t,
ast::BiLe,
debug_loc);
Result::new(bcx, And(bcx, llge, llle, debug_loc))
}
LowerBound(Result { bcx, val }) => {
compare_scalar_types(bcx, test_val, val, t, ast::BiGe)
compare_scalar_types(bcx,
test_val,
val,
t,
ast::BiGe,
debug_loc)
}
}
};
@ -1151,37 +1201,37 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
if i + 1 < len && (guarded || multi_pats || kind == CompareSliceLength) {
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
}
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb, DebugLoc::None);
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb, debug_loc);
}
_ => ()
}
} else if kind == Compare || kind == CompareSliceLength {
Br(bcx, else_cx.llbb, DebugLoc::None);
Br(bcx, else_cx.llbb, debug_loc);
}
let mut size = 0;
let mut unpacked = Vec::new();
match *opt {
Variant(disr_val, ref repr, _) => {
Variant(disr_val, ref repr, _, _) => {
let ExtractedBlock {vals: argvals, bcx: new_bcx} =
extract_variant_args(opt_cx, &**repr, disr_val, val);
size = argvals.len();
unpacked = argvals;
opt_cx = new_bcx;
}
SliceLengthEqual(len) => {
SliceLengthEqual(len, _) => {
let args = extract_vec_elems(opt_cx, left_ty, len, 0, val);
size = args.vals.len();
unpacked = args.vals.clone();
opt_cx = args.bcx;
}
SliceLengthGreaterOrEqual(before, after) => {
SliceLengthGreaterOrEqual(before, after, _) => {
let args = extract_vec_elems(opt_cx, left_ty, before, after, val);
size = args.vals.len();
unpacked = args.vals.clone();
opt_cx = args.bcx;
}
ConstantValue(_) | ConstantRange(_, _) => ()
ConstantValue(..) | ConstantRange(..) => ()
}
let opt_ms = enter_opt(opt_cx, pat_id, dm, m, opt, col, size, val);
let mut opt_vals = unpacked;
@ -1385,16 +1435,27 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
bindings_map: create_bindings_map(bcx, &*arm.pats[0], discr_expr, &*arm.body)
}).collect();
let mut static_inliner = StaticInliner::new(scope_cx.tcx());
let arm_pats: Vec<Vec<P<ast::Pat>>> = arm_datas.iter().map(|arm_data| {
arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect()
}).collect();
let mut pat_renaming_map = if scope_cx.sess().opts.debuginfo != NoDebugInfo {
Some(FnvHashMap())
} else {
None
};
let arm_pats: Vec<Vec<P<ast::Pat>>> = {
let mut static_inliner = StaticInliner::new(scope_cx.tcx(),
pat_renaming_map.as_mut());
arm_datas.iter().map(|arm_data| {
arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect()
}).collect()
};
let mut matches = Vec::new();
for (arm_data, pats) in arm_datas.iter().zip(arm_pats.iter()) {
matches.extend(pats.iter().map(|p| Match {
pats: vec![&**p],
data: arm_data,
bound_ptrs: Vec::new(),
pat_renaming_map: pat_renaming_map.as_ref()
}));
}

View File

@ -751,7 +751,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
RawNullablePointer { nndiscr, nnty, .. } => {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty));
val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None);
signed = false;
}
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
@ -770,7 +770,7 @@ fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &Disc
let llptrptr = GEPi(bcx, scrutinee, &discrfield[]);
let llptr = Load(bcx, llptrptr);
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)))
ICmp(bcx, cmp, llptr, C_null(val_ty(llptr)), DebugLoc::None)
}
/// Helper for cases where the discriminant is simply loaded.

View File

@ -57,7 +57,7 @@ use trans::closure;
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_integral};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{CrateContext, ExternMap, FunctionContext};
use trans::common::{Result};
use trans::common::{Result, NodeIdAndSpan};
use trans::common::{node_id_type, return_type_is_void};
use trans::common::{tydesc_info, type_is_immediate};
use trans::common::{type_is_zero_size, val_ty};
@ -66,7 +66,7 @@ use trans::consts;
use trans::context::SharedCrateContext;
use trans::controlflow;
use trans::datum;
use trans::debuginfo::{self, DebugLoc};
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
use trans::expr;
use trans::foreign;
use trans::glue;
@ -379,7 +379,8 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llty_ptr: Type,
info_ty: Ty<'tcx>,
size: ValueRef,
align: ValueRef)
align: ValueRef,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
let _icx = push_ctxt("malloc_raw_exchange");
@ -387,7 +388,8 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let r = callee::trans_lang_call(bcx,
require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem),
&[size, align],
None);
None,
debug_loc);
Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
}
@ -538,9 +540,10 @@ pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
t: Ty<'tcx>,
op: ast::BinOp_)
op: ast::BinOp_,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op));
let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op, debug_loc));
match t.sty {
ty::ty_tup(ref tys) if tys.is_empty() => f(nil_type),
@ -559,7 +562,8 @@ pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
lhs: ValueRef,
rhs: ValueRef,
nt: scalar_type,
op: ast::BinOp_)
op: ast::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
let _icx = push_ctxt("compare_scalar_values");
fn die(cx: Block) -> ! {
@ -586,7 +590,7 @@ pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ast::BiGe => llvm::RealOGE,
_ => die(cx)
};
return FCmp(cx, cmp, lhs, rhs);
return FCmp(cx, cmp, lhs, rhs, debug_loc);
}
signed_int => {
let cmp = match op {
@ -598,7 +602,7 @@ pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ast::BiGe => llvm::IntSGE,
_ => die(cx)
};
return ICmp(cx, cmp, lhs, rhs);
return ICmp(cx, cmp, lhs, rhs, debug_loc);
}
unsigned_int => {
let cmp = match op {
@ -610,7 +614,7 @@ pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
ast::BiGe => llvm::IntUGE,
_ => die(cx)
};
return ICmp(cx, cmp, lhs, rhs);
return ICmp(cx, cmp, lhs, rhs, debug_loc);
}
}
}
@ -621,7 +625,8 @@ pub fn compare_simd_types<'blk, 'tcx>(
rhs: ValueRef,
t: Ty<'tcx>,
size: uint,
op: ast::BinOp)
op: ast::BinOp_,
debug_loc: DebugLoc)
-> ValueRef {
let cmp = match t.sty {
ty::ty_float(_) => {
@ -632,7 +637,7 @@ pub fn compare_simd_types<'blk, 'tcx>(
cx.sess().bug("compare_simd_types: comparison operators \
not supported for floating point SIMD types")
},
ty::ty_uint(_) => match op.node {
ty::ty_uint(_) => match op {
ast::BiEq => llvm::IntEQ,
ast::BiNe => llvm::IntNE,
ast::BiLt => llvm::IntULT,
@ -641,7 +646,7 @@ pub fn compare_simd_types<'blk, 'tcx>(
ast::BiGe => llvm::IntUGE,
_ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
},
ty::ty_int(_) => match op.node {
ty::ty_int(_) => match op {
ast::BiEq => llvm::IntEQ,
ast::BiNe => llvm::IntNE,
ast::BiLt => llvm::IntSLT,
@ -657,7 +662,7 @@ pub fn compare_simd_types<'blk, 'tcx>(
// to get the correctly sized type. This will compile to a single instruction
// once the IR is converted to assembly if the SIMD instruction is supported
// by the target architecture.
SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty)
SExt(cx, ICmp(cx, cmp, lhs, rhs, debug_loc), return_ty)
}
// Iterates through the elements of a structural type.
@ -851,7 +856,7 @@ pub fn cast_shift_rhs<F, G>(op: ast::BinOp,
pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
cx: Block<'blk, 'tcx>,
span: Span,
call_info: NodeIdAndSpan,
divrem: ast::BinOp,
lhs: ValueRef,
rhs: ValueRef,
@ -864,14 +869,16 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
("attempted remainder with a divisor of zero",
"attempted remainder with overflow")
};
let debug_loc = call_info.debug_loc();
let (is_zero, is_signed) = match rhs_t.sty {
ty::ty_int(t) => {
let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
(ICmp(cx, llvm::IntEQ, rhs, zero), true)
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), true)
}
ty::ty_uint(t) => {
let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
(ICmp(cx, llvm::IntEQ, rhs, zero), false)
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false)
}
_ => {
cx.sess().bug(&format!("fail-if-zero on unexpected type: {}",
@ -879,7 +886,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
}
};
let bcx = with_cond(cx, is_zero, |bcx| {
controlflow::trans_fail(bcx, span, InternedString::new(zero_text))
controlflow::trans_fail(bcx, call_info, InternedString::new(zero_text))
});
// To quote LLVM's documentation for the sdiv instruction:
@ -908,12 +915,13 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(
_ => unreachable!(),
};
let minus_one = ICmp(bcx, llvm::IntEQ, rhs,
C_integral(llty, -1, false));
C_integral(llty, -1, false), debug_loc);
with_cond(bcx, minus_one, |bcx| {
let is_min = ICmp(bcx, llvm::IntEQ, lhs,
C_integral(llty, min, true));
C_integral(llty, min, true), debug_loc);
with_cond(bcx, is_min, |bcx| {
controlflow::trans_fail(bcx, span,
controlflow::trans_fail(bcx,
call_info,
InternedString::new(overflow_text))
})
})

View File

@ -856,22 +856,32 @@ pub fn FPCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef {
/* Comparisons */
pub fn ICmp(cx: Block, op: IntPredicate, lhs: ValueRef, rhs: ValueRef)
-> ValueRef {
pub fn ICmp(cx: Block,
op: IntPredicate,
lhs: ValueRef,
rhs: ValueRef,
debug_loc: DebugLoc)
-> ValueRef {
unsafe {
if cx.unreachable.get() {
return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
}
debug_loc.apply(cx.fcx);
B(cx).icmp(op, lhs, rhs)
}
}
pub fn FCmp(cx: Block, op: RealPredicate, lhs: ValueRef, rhs: ValueRef)
-> ValueRef {
pub fn FCmp(cx: Block,
op: RealPredicate,
lhs: ValueRef,
rhs: ValueRef,
debug_loc: DebugLoc)
-> ValueRef {
unsafe {
if cx.unreachable.get() {
return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref());
}
debug_loc.apply(cx.fcx);
B(cx).fcmp(op, lhs, rhs)
}
}
@ -941,9 +951,17 @@ pub fn Call(cx: Block,
B(cx).call(fn_, args, attributes)
}
pub fn CallWithConv(cx: Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv,
attributes: Option<AttrBuilder>) -> ValueRef {
if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
pub fn CallWithConv(cx: Block,
fn_: ValueRef,
args: &[ValueRef],
conv: CallConv,
attributes: Option<AttrBuilder>,
debug_loc: DebugLoc)
-> ValueRef {
if cx.unreachable.get() {
return _UndefReturn(cx, fn_);
}
debug_loc.apply(cx.fcx);
B(cx).call_with_conv(fn_, args, conv, attributes)
}

View File

@ -36,8 +36,8 @@ use trans::callee;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::closure;
use trans::common;
use trans::common::*;
use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
ExprOrMethodCall, FunctionContext, MethodCallKey};
use trans::consts;
use trans::datum::*;
use trans::debuginfo::{DebugLoc, ToDebugLoc};
@ -136,7 +136,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
ref_expr: &ast::Expr)
-> Callee<'blk, 'tcx> {
debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
let expr_ty = node_id_type(bcx, ref_expr.id);
let expr_ty = common::node_id_type(bcx, ref_expr.id);
match def {
def::DefFn(did, _) if {
let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
@ -147,8 +147,9 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
_ => false
}
} => {
let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
let substs = common::node_id_substs(bcx.ccx(),
ExprId(ref_expr.id),
bcx.fcx.param_substs);
Callee {
bcx: bcx,
data: NamedTupleConstructor(substs, 0)
@ -158,8 +159,9 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
_ => false
} => {
let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
let substs = common::node_id_substs(bcx.ccx(),
ExprId(ref_expr.id),
bcx.fcx.param_substs);
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
}
@ -178,8 +180,9 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
}
def::DefVariant(tid, vid, _) => {
let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
let substs = common::node_id_substs(bcx.ccx(),
ExprId(ref_expr.id),
bcx.fcx.param_substs);
// Nullary variants are not callable
assert!(vinfo.args.len() > 0);
@ -190,8 +193,9 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
}
}
def::DefStruct(_) => {
let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
let substs = common::node_id_substs(bcx.ccx(),
ExprId(ref_expr.id),
bcx.fcx.param_substs);
Callee {
bcx: bcx,
data: NamedTupleConstructor(substs, 0)
@ -226,7 +230,7 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_fn_ref");
let substs = node_id_substs(ccx, node, param_substs);
let substs = common::node_id_substs(ccx, node, param_substs);
debug!("trans_fn_ref(def_id={}, node={:?}, substs={})",
def_id.repr(ccx.tcx()),
node,
@ -269,7 +273,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
let _icx = push_ctxt("trans_fn_pointer_shim");
let tcx = ccx.tcx();
let bare_fn_ty = erase_regions(tcx, &bare_fn_ty);
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
Some(&llval) => { return llval; }
None => { }
@ -352,7 +356,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
);
bcx = trans_call_inner(bcx,
None,
DebugLoc::None,
bare_fn_ty,
|bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
ArgVals(&llargs[]),
@ -515,7 +519,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
param_substs,
&ref_ty);
let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
if llptrty != val_ty(val) {
if llptrty != common::val_ty(val) {
let val = consts::ptrcast(val, llptrty);
return Datum::new(val, ref_ty, Rvalue::new(ByValue));
}
@ -563,7 +567,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
// other weird situations. Annoying.
let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
let llptrty = llty.ptr_to();
if val_ty(val) != llptrty {
if common::val_ty(val) != llptrty {
debug!("trans_fn_ref_with_vtables(): casting pointer!");
val = consts::ptrcast(val, llptrty);
} else {
@ -577,34 +581,34 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
// Translating calls
pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>,
call_ex: &ast::Expr,
call_expr: &ast::Expr,
f: &ast::Expr,
args: CallArgs<'a, 'tcx>,
dest: expr::Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_call");
trans_call_inner(in_cx,
Some(common::expr_info(call_ex)),
expr_ty_adjusted(in_cx, f),
call_expr.debug_loc(),
common::expr_ty_adjusted(in_cx, f),
|cx, _| trans(cx, f),
args,
Some(dest)).bcx
}
pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
call_ex: &ast::Expr,
call_expr: &ast::Expr,
rcvr: &ast::Expr,
args: CallArgs<'a, 'tcx>,
dest: expr::Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_method_call");
debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx()));
let method_call = MethodCall::expr(call_ex.id);
debug!("trans_method_call(call_expr={})", call_expr.repr(bcx.tcx()));
let method_call = MethodCall::expr(call_expr.id);
let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
trans_call_inner(
bcx,
Some(common::expr_info(call_ex)),
monomorphize_type(bcx, method_ty),
call_expr.debug_loc(),
common::monomorphize_type(bcx, method_ty),
|cx, arg_cleanup_scope| {
meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
},
@ -615,7 +619,8 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
did: ast::DefId,
args: &[ValueRef],
dest: Option<expr::Dest>)
dest: Option<expr::Dest>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
let fty = if did.krate == ast::LOCAL_CRATE {
ty::node_id_to_type(bcx.tcx(), did.node)
@ -623,7 +628,7 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
csearch::get_type(bcx.tcx(), did).ty
};
callee::trans_call_inner(bcx,
None,
debug_loc,
fty,
|bcx, _| {
trans_fn_ref_with_substs_to_callee(bcx,
@ -646,7 +651,7 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
/// For non-lang items, `dest` is always Some, and hence the result is written into memory
/// somewhere. Nonetheless we return the actual return value of the function.
pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
call_info: Option<NodeIdAndSpan>,
debug_loc: DebugLoc,
callee_ty: Ty<'tcx>,
get_callee: F,
args: CallArgs<'a, 'tcx>,
@ -687,7 +692,13 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
assert!(abi == synabi::RustIntrinsic);
assert!(dest.is_some());
let call_info = call_info.expect("no call info for intrinsic call?");
let call_info = match debug_loc {
DebugLoc::At(id, span) => NodeIdAndSpan { id: id, span: span },
DebugLoc::None => {
bcx.sess().bug("No call info for intrinsic call?")
}
};
return intrinsic::trans_intrinsic_call(bcx, node, callee_ty,
arg_cleanup_scope, args,
dest.unwrap(), substs,
@ -703,7 +714,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
disr,
args,
dest.unwrap(),
call_info.debug_loc());
debug_loc);
}
};
@ -724,12 +735,12 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
};
if !is_rust_fn ||
type_of::return_uses_outptr(ccx, ret_ty) ||
type_needs_drop(bcx.tcx(), ret_ty) {
common::type_needs_drop(bcx.tcx(), ret_ty) {
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
if type_is_zero_size(ccx, ret_ty) {
if common::type_is_zero_size(ccx, ret_ty) {
let llty = type_of::type_of(ccx, ret_ty);
Some(C_undef(llty.ptr_to()))
Some(common::C_undef(llty.ptr_to()))
} else {
Some(alloc_ty(bcx, ret_ty, "__llret"))
}
@ -781,7 +792,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
llfn,
&llargs[],
callee_ty,
call_info.debug_loc());
debug_loc);
bcx = b;
llresult = llret;
@ -790,7 +801,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
match (opt_llretslot, ret_ty) {
(Some(llretslot), ty::FnConverging(ret_ty)) => {
if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) &&
!type_is_zero_size(bcx.ccx(), ret_ty)
!common::type_is_zero_size(bcx.ccx(), ret_ty)
{
store_ty(bcx, llret, llretslot, ret_ty)
}
@ -804,7 +815,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let mut llargs = Vec::new();
let arg_tys = match args {
ArgExprs(a) => a.iter().map(|x| expr_ty(bcx, &**x)).collect(),
ArgExprs(a) => a.iter().map(|x| common::expr_ty(bcx, &**x)).collect(),
_ => panic!("expected arg exprs.")
};
bcx = trans_args(bcx,
@ -816,9 +827,13 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
abi);
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
bcx = foreign::trans_native_call(bcx, callee_ty,
llfn, opt_llretslot.unwrap(),
&llargs[], arg_tys);
bcx = foreign::trans_native_call(bcx,
callee_ty,
llfn,
opt_llretslot.unwrap(),
&llargs[],
arg_tys,
debug_loc);
}
fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_cleanup_scope);
@ -831,7 +846,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
bcx = glue::drop_ty(bcx,
llretslot,
ret_ty,
call_info.debug_loc());
debug_loc);
call_lifetime_end(bcx, llretslot);
}
_ => {}
@ -892,7 +907,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>(
// Now untuple the rest of the arguments.
let tuple_expr = &arg_exprs[1];
let tuple_type = node_id_type(bcx, tuple_expr.id);
let tuple_type = common::node_id_type(bcx, tuple_expr.id);
match tuple_type.sty {
ty::ty_tup(ref field_types) => {
@ -1014,7 +1029,7 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
}
let arg_ty = if i >= num_formal_args {
assert!(variadic);
expr_ty_adjusted(cx, &**arg_expr)
common::expr_ty_adjusted(cx, &**arg_expr)
} else {
arg_tys[i]
};

View File

@ -940,11 +940,12 @@ impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> {
bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
debug_loc.apply(bcx.fcx);
match self.heap {
HeapExchange => {
glue::trans_exchange_free_ty(bcx, self.ptr, self.content_ty)
glue::trans_exchange_free_ty(bcx,
self.ptr,
self.content_ty,
debug_loc)
}
}
}
@ -975,11 +976,13 @@ impl<'tcx> Cleanup<'tcx> for FreeSlice {
bcx: Block<'blk, 'tcx>,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
debug_loc.apply(bcx.fcx);
match self.heap {
HeapExchange => {
glue::trans_exchange_free_dyn(bcx, self.ptr, self.size, self.align)
glue::trans_exchange_free_dyn(bcx,
self.ptr,
self.size,
self.align,
debug_loc)
}
}
}

View File

@ -28,7 +28,6 @@ use util::ppaux::Repr;
use syntax::ast;
use syntax::ast::Ident;
use syntax::ast_util;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::parse::token;
use syntax::visit::Visitor;
@ -361,31 +360,32 @@ pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
sp: Span,
call_info: NodeIdAndSpan,
fail_str: InternedString)
-> Block<'blk, 'tcx> {
let ccx = bcx.ccx();
let _icx = push_ctxt("trans_fail_value");
let v_str = C_str_slice(ccx, fail_str);
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name[]);
let filename = C_str_slice(ccx, filename);
let line = C_uint(ccx, loc.line);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const, ast::MutImmutable);
let args = vec!(expr_file_line);
let did = langcall(bcx, Some(sp), "", PanicFnLangItem);
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
let bcx = callee::trans_lang_call(bcx,
did,
&args[],
Some(expr::Ignore)).bcx;
Some(expr::Ignore),
call_info.debug_loc()).bcx;
Unreachable(bcx);
return bcx;
}
pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
sp: Span,
call_info: NodeIdAndSpan,
index: ValueRef,
len: ValueRef)
-> Block<'blk, 'tcx> {
@ -393,7 +393,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let _icx = push_ctxt("trans_fail_bounds_check");
// Extract the file/line from the span
let loc = bcx.sess().codemap().lookup_char_pos(sp.lo);
let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo);
let filename = token::intern_and_get_ident(&loc.file.name[]);
// Invoke the lang item
@ -402,11 +402,12 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let file_line_const = C_struct(ccx, &[filename, line], false);
let file_line = consts::const_addr_of(ccx, file_line_const, ast::MutImmutable);
let args = vec!(file_line, index, len);
let did = langcall(bcx, Some(sp), "", PanicBoundsCheckFnLangItem);
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
let bcx = callee::trans_lang_call(bcx,
did,
&args[],
Some(expr::Ignore)).bcx;
Some(expr::Ignore),
call_info.debug_loc()).bcx;
Unreachable(bcx);
return bcx;
}

View File

@ -1113,7 +1113,7 @@ pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DebugLoc {
At(ast::NodeId, Span),
None

View File

@ -586,7 +586,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let contents_ty = expr_ty(bcx, &**contents);
match box_ty.sty {
ty::ty_uniq(..) => {
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
trans_uniq_expr(bcx, expr, box_ty, &**contents, contents_ty)
}
_ => bcx.sess().span_bug(expr.span,
"expected unique box")
@ -696,6 +696,8 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let ccx = bcx.ccx();
let mut bcx = bcx;
let index_expr_debug_loc = index_expr.debug_loc();
// Check for overloaded index.
let method_ty = ccx.tcx()
.method_map
@ -778,16 +780,20 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("trans_index: base {}", bcx.val_to_string(base));
debug!("trans_index: len {}", bcx.val_to_string(len));
let bounds_check = ICmp(bcx, llvm::IntUGE, ix_val, len);
let bounds_check = ICmp(bcx,
llvm::IntUGE,
ix_val,
len,
index_expr_debug_loc);
let expect = ccx.get_intrinsic(&("llvm.expect.i1"));
let expected = Call(bcx,
expect,
&[bounds_check, C_bool(ccx, false)],
None,
index_expr.debug_loc());
index_expr_debug_loc);
bcx = with_cond(bcx, expected, |bcx| {
controlflow::trans_fail_bounds_check(bcx,
index_expr.span,
expr_info(index_expr),
ix_val,
len)
});
@ -1574,7 +1580,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
}
ast::UnUniq => {
trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
trans_uniq_expr(bcx, expr, un_ty, sub_expr, expr_ty(bcx, sub_expr))
}
ast::UnDeref => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
@ -1584,6 +1590,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
box_expr: &ast::Expr,
box_ty: Ty<'tcx>,
contents: &ast::Expr,
contents_ty: Ty<'tcx>)
@ -1595,7 +1602,12 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let size = llsize_of(bcx.ccx(), llty);
let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty));
let llty_ptr = llty.ptr_to();
let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align);
let Result { bcx, val } = malloc_raw_dyn(bcx,
llty_ptr,
box_ty,
size,
align,
box_expr.debug_loc());
// Unique boxes do not allocate for zero-size types. The standard library
// may assume that `free` is never called on the pointer returned for
// `Box<ZeroSizeType>`.
@ -1697,8 +1709,12 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
FDiv(bcx, lhs, rhs, binop_debug_loc)
} else {
// Only zero-check integers; fp /0 is NaN
bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
op, lhs, rhs, rhs_t);
bcx = base::fail_if_zero_or_overflows(bcx,
expr_info(binop_expr),
op,
lhs,
rhs,
rhs_t);
if is_signed {
SDiv(bcx, lhs, rhs, binop_debug_loc)
} else {
@ -1711,7 +1727,8 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
FRem(bcx, lhs, rhs, binop_debug_loc)
} else {
// Only zero-check integers; fp %0 is NaN
bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
bcx = base::fail_if_zero_or_overflows(bcx,
expr_info(binop_expr),
op, lhs, rhs, rhs_t);
if is_signed {
SRem(bcx, lhs, rhs, binop_debug_loc)
@ -1733,9 +1750,21 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
ast::BiEq | ast::BiNe | ast::BiLt | ast::BiGe | ast::BiLe | ast::BiGt => {
if ty::type_is_scalar(rhs_t) {
unpack_result!(bcx, base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op.node))
unpack_result!(bcx,
base::compare_scalar_types(bcx,
lhs,
rhs,
rhs_t,
op.node,
binop_debug_loc))
} else if is_simd {
base::compare_simd_types(bcx, lhs, rhs, intype, ty::simd_size(tcx, lhs_t), op)
base::compare_simd_types(bcx,
lhs,
rhs,
intype,
ty::simd_size(tcx, lhs_t),
op.node,
binop_debug_loc)
} else {
bcx.tcx().sess.span_bug(binop_expr.span, "comparison operator unsupported for type")
}
@ -1845,7 +1874,7 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Result<'blk, 'tcx> {
let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty;
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
expr.debug_loc(),
monomorphize_type(bcx, method_ty),
|bcx, arg_cleanup_scope| {
meth::trans_method_callee(bcx,
@ -1872,7 +1901,7 @@ fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
all_args.extend(args.iter().map(|e| &**e));
unpack_result!(bcx,
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
expr.debug_loc(),
monomorphize_type(bcx,
method_type),
|bcx, arg_cleanup_scope| {

View File

@ -18,6 +18,7 @@ use trans::base;
use trans::build::*;
use trans::cabi;
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
@ -218,7 +219,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llfn: ValueRef,
llretptr: ValueRef,
llargs_rust: &[ValueRef],
passed_arg_tys: Vec<Ty<'tcx>>)
passed_arg_tys: Vec<Ty<'tcx>>,
call_debug_loc: DebugLoc)
-> Block<'blk, 'tcx>
{
let ccx = bcx.ccx();
@ -370,7 +372,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
llfn,
&llargs_foreign[],
cc,
Some(attrs));
Some(attrs),
call_debug_loc);
// If the function we just called does not use an outpointer,
// store the result into the rust outpointer. Cast the outpointer

View File

@ -45,25 +45,39 @@ use std::ffi::CString;
use syntax::ast;
use syntax::parse::token;
pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
size: ValueRef, align: ValueRef)
pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
v: ValueRef,
size: ValueRef,
align: ValueRef,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_exchange_free");
let ccx = cx.ccx();
callee::trans_lang_call(cx,
langcall(cx, None, "", ExchangeFreeFnLangItem),
&[PointerCast(cx, v, Type::i8p(ccx)), size, align],
Some(expr::Ignore)).bcx
Some(expr::Ignore),
debug_loc).bcx
}
pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
size: u64, align: u32) -> Block<'blk, 'tcx> {
trans_exchange_free_dyn(cx, v, C_uint(cx.ccx(), size),
C_uint(cx.ccx(), align))
pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
v: ValueRef,
size: u64,
align: u32,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
trans_exchange_free_dyn(cx,
v,
C_uint(cx.ccx(), size),
C_uint(cx.ccx(), align),
debug_loc)
}
pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
content_ty: Ty<'tcx>) -> Block<'blk, 'tcx> {
pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ptr: ValueRef,
content_ty: Ty<'tcx>,
debug_loc: DebugLoc)
-> Block<'blk, 'tcx> {
assert!(type_is_sized(bcx.ccx().tcx(), content_ty));
let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
@ -71,7 +85,7 @@ pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
// `Box<ZeroSizeType>` does not allocate.
if content_size != 0 {
let content_align = align_of(bcx.ccx(), content_ty);
trans_exchange_free(bcx, ptr, content_size, content_align)
trans_exchange_free(bcx, ptr, content_size, content_align, debug_loc)
} else {
bcx
}
@ -328,7 +342,11 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
// Return the sum of sizes and max of aligns.
let size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
let align = Select(bcx,
ICmp(bcx, llvm::IntULT, sized_align, unsized_align),
ICmp(bcx,
llvm::IntULT,
sized_align,
unsized_align,
DebugLoc::None),
sized_align,
unsized_align);
(size, align)
@ -394,7 +412,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
let info = Load(bcx, info);
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
trans_exchange_free_dyn(bcx, llbox, llsize, llalign)
trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
})
}
_ => {
@ -404,7 +422,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
trans_exchange_free_ty(bcx, llbox, content_ty)
trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
})
}
}

View File

@ -667,7 +667,7 @@ pub fn trans_object_shim<'a, 'tcx>(
method_offset_in_vtable);
bcx = trans_call_inner(bcx,
None,
DebugLoc::None,
method_bare_fn_ty,
|bcx, _| trans_trait_callee_from_llval(bcx,
method_bare_fn_ty,

View File

@ -73,11 +73,19 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let unit_size = llsize_of_alloc(ccx, llty);
if unit_size != 0 {
let len = get_len(bcx, vptr);
let not_empty = ICmp(bcx, llvm::IntNE, len, C_uint(ccx, 0us));
let not_empty = ICmp(bcx,
llvm::IntNE,
len,
C_uint(ccx, 0us),
DebugLoc::None);
with_cond(bcx, not_empty, |bcx| {
let llalign = C_uint(ccx, machine::llalign_of_min(ccx, llty));
let size = Mul(bcx, C_uint(ccx, unit_size), len, DebugLoc::None);
glue::trans_exchange_free_dyn(bcx, dataptr, size, llalign)
glue::trans_exchange_free_dyn(bcx,
dataptr,
size,
llalign,
DebugLoc::None)
})
} else {
bcx
@ -439,7 +447,7 @@ pub fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
{ // i < count
let lhs = Load(cond_bcx, loop_counter);
let rhs = count;
let cond_val = ICmp(cond_bcx, llvm::IntULT, lhs, rhs);
let cond_val = ICmp(cond_bcx, llvm::IntULT, lhs, rhs, DebugLoc::None);
CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);
}
@ -493,7 +501,7 @@ pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
let data_ptr =
Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]);
let not_yet_at_end =
ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr);
ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr, DebugLoc::None);
let body_bcx = fcx.new_temp_block("iter_vec_loop_body");
let next_bcx = fcx.new_temp_block("iter_vec_next");
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb, DebugLoc::None);

View File

@ -0,0 +1,92 @@
// Copyright 2013-2015 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-android: FIXME(#10381)
// min-lldb-version: 310
// compile-flags:-g
#![allow(unused_variables)]
#![allow(dead_code)]
#![omit_gdb_pretty_printer_section]
// This test makes sure that the compiler doesn't crash when trying to assign
// debug locations to 'constant' patterns in match expressions.
const CONSTANT: u64 = 3;
struct Struct {
a: isize,
b: usize,
}
const STRUCT: Struct = Struct { a: 1, b: 2 };
struct TupleStruct(u32);
const TUPLE_STRUCT: TupleStruct = TupleStruct(4);
enum Enum {
Variant1(char),
Variant2 { a: u8 },
Variant3
}
const VARIANT1: Enum = Enum::Variant1('v');
const VARIANT2: Enum = Enum::Variant2 { a: 2 };
const VARIANT3: Enum = Enum::Variant3;
const STRING: &'static str = "String";
fn main() {
match 1 {
CONSTANT => {}
_ => {}
};
// if let 3 = CONSTANT {}
match (Struct { a: 2, b: 2 }) {
STRUCT => {}
_ => {}
};
// if let STRUCT = STRUCT {}
match TupleStruct(3) {
TUPLE_STRUCT => {}
_ => {}
};
// if let TupleStruct(4) = TUPLE_STRUCT {}
match VARIANT3 {
VARIANT1 => {},
VARIANT2 => {},
VARIANT3 => {},
_ => {}
};
match (VARIANT3, VARIANT2) {
(VARIANT1, VARIANT3) => {},
(VARIANT2, VARIANT2) => {},
(VARIANT3, VARIANT1) => {},
_ => {}
};
// if let VARIANT1 = Enum::Variant3 {}
// if let VARIANT2 = Enum::Variant3 {}
// if let VARIANT3 = Enum::Variant3 {}
match "abc" {
STRING => {},
_ => {}
}
if let STRING = "def" {}
}