Skip to content

Commit 26be17b

Browse files
committed
---
yaml --- r: 105175 b: refs/heads/snap-stage3 c: 7febdb7 h: refs/heads/master i: 105173: eb63f3a 105171: 1df1ca8 105167: 9c9c858 v: v3
1 parent 491dffa commit 26be17b

File tree

13 files changed

+164
-343
lines changed

13 files changed

+164
-343
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 62f1d68439dcfd509eaca29887afa97f22938373
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: e560db7dab16ffe77d32a7ca14376fd54d9c2dfc
4+
refs/heads/snap-stage3: 7febdb7b15681a6a70da191128a9552f35ed5644
55
refs/heads/try: db814977d07bd798feb24f6b74c00800ef458a13
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/librustc/middle/trans/_match.rs

Lines changed: 41 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -256,23 +256,43 @@ enum Opt {
256256
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
257257
}
258258

259-
fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> @ast::Expr {
260-
match *a {
261-
ExprLit(existing_a_expr) => existing_a_expr,
262-
ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap(),
263-
UnitLikeStructLit(_) => fail!("lit_to_expr: unexpected struct lit"),
264-
}
265-
}
266-
267259
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
268260
match (a, b) {
269-
(&lit(UnitLikeStructLit(a)), &lit(UnitLikeStructLit(b))) => a == b,
270261
(&lit(a), &lit(b)) => {
271-
let a_expr = lit_to_expr(tcx, &a);
272-
let b_expr = lit_to_expr(tcx, &b);
273-
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
274-
Some(val1) => val1 == 0,
275-
None => fail!("compare_list_exprs: type mismatch"),
262+
match (a, b) {
263+
(UnitLikeStructLit(a), UnitLikeStructLit(b)) => a == b,
264+
_ => {
265+
let a_expr;
266+
match a {
267+
ExprLit(existing_a_expr) => a_expr = existing_a_expr,
268+
ConstLit(a_const) => {
269+
let e = const_eval::lookup_const_by_id(tcx, a_const);
270+
a_expr = e.unwrap();
271+
}
272+
UnitLikeStructLit(_) => {
273+
fail!("UnitLikeStructLit should have been handled \
274+
above")
275+
}
276+
}
277+
278+
let b_expr;
279+
match b {
280+
ExprLit(existing_b_expr) => b_expr = existing_b_expr,
281+
ConstLit(b_const) => {
282+
let e = const_eval::lookup_const_by_id(tcx, b_const);
283+
b_expr = e.unwrap();
284+
}
285+
UnitLikeStructLit(_) => {
286+
fail!("UnitLikeStructLit should have been handled \
287+
above")
288+
}
289+
}
290+
291+
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
292+
Some(val1) => val1 == 0,
293+
None => fail!("compare_list_exprs: type mismatch"),
294+
}
295+
}
276296
}
277297
}
278298
(&range(a1, a2), &range(b1, b2)) => {
@@ -290,42 +310,6 @@ fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
290310
}
291311
}
292312

293-
fn opt_overlap(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
294-
match (a, b) {
295-
(&lit(a), &lit(b)) => {
296-
let a_expr = lit_to_expr(tcx, &a);
297-
let b_expr = lit_to_expr(tcx, &b);
298-
match const_eval::compare_lit_exprs(tcx, a_expr, b_expr) {
299-
Some(val1) => val1 == 0,
300-
None => fail!("opt_overlap: type mismatch"),
301-
}
302-
}
303-
304-
(&range(a1, a2), &range(b1, b2)) => {
305-
let m1 = const_eval::compare_lit_exprs(tcx, a1, b2);
306-
let m2 = const_eval::compare_lit_exprs(tcx, b1, a2);
307-
match (m1, m2) {
308-
// two ranges [a1, a2] and [b1, b2] overlap iff:
309-
// a1 <= b2 && b1 <= a2
310-
(Some(val1), Some(val2)) => (val1 <= 0 && val2 <= 0),
311-
_ => fail!("opt_overlap: type mismatch"),
312-
}
313-
}
314-
315-
(&range(a1, a2), &lit(b)) | (&lit(b), &range(a1, a2)) => {
316-
let b_expr = lit_to_expr(tcx, &b);
317-
let m1 = const_eval::compare_lit_exprs(tcx, a1, b_expr);
318-
let m2 = const_eval::compare_lit_exprs(tcx, a2, b_expr);
319-
match (m1, m2) {
320-
// b is in range [a1, a2] iff a1 <= b and b <= a2
321-
(Some(val1), Some(val2)) => (val1 <= 0 && 0 <= val2),
322-
_ => fail!("opt_overlap: type mismatch"),
323-
}
324-
}
325-
_ => fail!("opt_overlap: expect lit or range")
326-
}
327-
}
328-
329313
pub enum opt_result<'a> {
330314
single_result(Result<'a>),
331315
lower_bound(Result<'a>),
@@ -506,7 +490,7 @@ fn assert_is_binding_or_wild(bcx: &Block, p: @ast::Pat) {
506490
}
507491
}
508492

509-
type enter_pat<'a> = 'a |@ast::Pat| -> Option<Vec<@ast::Pat>>;
493+
type enter_pat<'a> = 'a |@ast::Pat| -> Option<Vec<@ast::Pat> >;
510494

511495
fn enter_match<'r,'b>(
512496
bcx: &'b Block<'b>,
@@ -648,30 +632,16 @@ fn enter_opt<'r,'b>(
648632
let tcx = bcx.tcx();
649633
let dummy = @ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
650634
let mut i = 0;
651-
// By the virtue of fact that we are in `trans` already, `enter_opt` is able
652-
// to prune sub-match tree aggressively based on exact equality. But when it
653-
// comes to literal or range, that strategy may lead to wrong result if there
654-
// are guard function or multiple patterns inside tuple; in that case, pruning
655-
// based on the overlap of patterns is required.
656-
//
657-
// Ideally, when constructing the sub-match tree for certain arm, only those
658-
// arms beneath it matter. But that isn't how algorithm works right now and
659-
// all other arms are taken into consideration when computing `guarded` below.
660-
// That is ok since each round of `compile_submatch` guarantees to trim one
661-
// "column" of arm patterns and the algorithm will converge.
662-
let guarded = m.iter().any(|x| x.data.arm.guard.is_some());
663-
let multi_pats = m.len() > 0 && m[0].pats.len() > 1;
664635
enter_match(bcx, tcx.def_map, m, col, val, |p| {
665636
let answer = match p.node {
666637
ast::PatEnum(..) |
667638
ast::PatIdent(_, _, None) if pat_is_const(tcx.def_map, p) => {
668639
let const_def = tcx.def_map.borrow().get_copy(&p.id);
669640
let const_def_id = ast_util::def_id_of_def(const_def);
670-
let konst = lit(ConstLit(const_def_id));
671-
match guarded || multi_pats {
672-
false if opt_eq(tcx, &konst, opt) => Some(Vec::new()),
673-
true if opt_overlap(tcx, &konst, opt) => Some(Vec::new()),
674-
_ => None,
641+
if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) {
642+
Some(Vec::new())
643+
} else {
644+
None
675645
}
676646
}
677647
ast::PatEnum(_, ref subpats) => {
@@ -696,20 +666,10 @@ fn enter_opt<'r,'b>(
696666
}
697667
}
698668
ast::PatLit(l) => {
699-
let lit_expr = lit(ExprLit(l));
700-
match guarded || multi_pats {
701-
false if opt_eq(tcx, &lit_expr, opt) => Some(Vec::new()),
702-
true if opt_overlap(tcx, &lit_expr, opt) => Some(Vec::new()),
703-
_ => None,
704-
}
669+
if opt_eq(tcx, &lit(ExprLit(l)), opt) {Some(Vec::new())} else {None}
705670
}
706671
ast::PatRange(l1, l2) => {
707-
let rng = range(l1, l2);
708-
match guarded || multi_pats {
709-
false if opt_eq(tcx, &rng, opt) => Some(Vec::new()),
710-
true if opt_overlap(tcx, &rng, opt) => Some(Vec::new()),
711-
_ => None,
712-
}
672+
if opt_eq(tcx, &range(l1, l2), opt) {Some(Vec::new())} else {None}
713673
}
714674
ast::PatStruct(_, ref field_pats, _) => {
715675
if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {

branches/snap-stage3/src/librustc/middle/trans/base.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
246246
pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
247247
inputs: &[ty::t], output: ty::t,
248248
name: &str) -> ValueRef {
249+
use middle::ty::{FreeRegion, BrAnon, ReFree, ReLateBound};
249250
let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
250251
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
251252

@@ -265,7 +266,17 @@ pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
265266
unsafe {
266267
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
267268
}
268-
}
269+
},
270+
// When a reference in an argument has no named lifetime, it's
271+
// impossible for that reference to escape this function(ie, be
272+
// returned).
273+
ty::ty_rptr(ReFree(FreeRegion { scope_id: _, bound_region: BrAnon(_) }), _) |
274+
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
275+
debug!("marking argument of {} as nocapture because of anonymous lifetime", name);
276+
unsafe {
277+
llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
278+
}
279+
},
269280
_ => {
270281
// For non-immediate arguments the callee gets its own copy of
271282
// the value on the stack, so there are no aliases

branches/snap-stage3/src/librustc/middle/trans/callee.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::slice;
2020

2121
use back::abi;
2222
use driver::session;
23-
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
23+
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute, NoCaptureAttribute};
2424
use lib::llvm::llvm;
2525
use metadata::csearch;
2626
use middle::trans::base;
@@ -661,9 +661,15 @@ pub fn trans_call_inner<'a>(
661661
llargs.push(opt_llretslot.unwrap());
662662
}
663663

664+
// start at 1, because index 0 is the return value of the llvm func
665+
let mut first_arg_offset = 1;
666+
664667
// Push the environment (or a trait object's self).
665668
match (llenv, llself) {
666-
(Some(llenv), None) => llargs.push(llenv),
669+
(Some(llenv), None) => {
670+
first_arg_offset += 1;
671+
llargs.push(llenv)
672+
},
667673
(None, Some(llself)) => llargs.push(llself),
668674
_ => {}
669675
}
@@ -682,6 +688,11 @@ pub fn trans_call_inner<'a>(
682688
let mut attrs = Vec::new();
683689
if type_of::return_uses_outptr(ccx, ret_ty) {
684690
attrs.push((1, StructRetAttribute));
691+
// The outptr can be noalias and nocapture because it's entirely
692+
// invisible to the program.
693+
attrs.push((1, NoAliasAttribute));
694+
attrs.push((1, NoCaptureAttribute));
695+
first_arg_offset += 1;
685696
}
686697

687698
// The `noalias` attribute on the return value is useful to a
@@ -695,6 +706,30 @@ pub fn trans_call_inner<'a>(
695706
_ => {}
696707
}
697708

709+
debug!("trans_callee_inner: first_arg_offset={}", first_arg_offset);
710+
711+
for (idx, &t) in ty::ty_fn_args(callee_ty).iter().enumerate().map(|(i, v)| (i+first_arg_offset, v)) {
712+
use middle::ty::{FreeRegion, BrAnon, ReFree, ReLateBound};
713+
if !type_is_immediate(ccx, t) {
714+
// if it's not immediate, we have a program-invisible pointer,
715+
// which it can't possibly capture
716+
attrs.push((idx, NoCaptureAttribute));
717+
debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx);
718+
continue;
719+
}
720+
721+
let t_ = ty::get(t);
722+
match t_.sty {
723+
ty::ty_rptr(ReFree(FreeRegion { scope_id: _, bound_region: BrAnon(_) }), _) |
724+
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
725+
726+
debug!("trans_callee_inner: argument {} nocapture because of anonymous lifetime", idx);
727+
attrs.push((idx, NoCaptureAttribute));
728+
},
729+
_ => { }
730+
}
731+
}
732+
698733
// Invoke the actual rust fn and update bcx/llresult.
699734
let (llret, b) = base::invoke(bcx,
700735
llfn,

branches/snap-stage3/src/libsyntax/parse/parser.rs

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ pub enum PathParsingMode {
111111
LifetimeAndTypesAndBounds,
112112
}
113113

114+
/// A pair of a path segment and group of type parameter bounds. (See `ast.rs`
115+
/// for the definition of a path segment.)
116+
struct PathSegmentAndBoundSet {
117+
segment: ast::PathSegment,
118+
bound_set: Option<OwnedSlice<TyParamBound>>,
119+
}
120+
114121
/// A path paired with optional type bounds.
115122
pub struct PathAndBounds {
116123
path: ast::Path,
@@ -1507,14 +1514,24 @@ impl<'a> Parser<'a> {
15071514
// First, parse an identifier.
15081515
let identifier = self.parse_ident();
15091516

1517+
// Next, parse a colon and bounded type parameters, if applicable.
1518+
let bound_set = if mode == LifetimeAndTypesAndBounds {
1519+
self.parse_optional_ty_param_bounds()
1520+
} else {
1521+
None
1522+
};
1523+
15101524
// Parse the '::' before type parameters if it's required. If
15111525
// it is required and wasn't present, then we're done.
15121526
if mode == LifetimeAndTypesWithColons &&
15131527
!self.eat(&token::MOD_SEP) {
1514-
segments.push(ast::PathSegment {
1515-
identifier: identifier,
1516-
lifetimes: Vec::new(),
1517-
types: OwnedSlice::empty(),
1528+
segments.push(PathSegmentAndBoundSet {
1529+
segment: ast::PathSegment {
1530+
identifier: identifier,
1531+
lifetimes: Vec::new(),
1532+
types: OwnedSlice::empty(),
1533+
},
1534+
bound_set: bound_set
15181535
});
15191536
break
15201537
}
@@ -1531,10 +1548,13 @@ impl<'a> Parser<'a> {
15311548
};
15321549

15331550
// Assemble and push the result.
1534-
segments.push(ast::PathSegment {
1535-
identifier: identifier,
1536-
lifetimes: lifetimes,
1537-
types: types,
1551+
segments.push(PathSegmentAndBoundSet {
1552+
segment: ast::PathSegment {
1553+
identifier: identifier,
1554+
lifetimes: lifetimes,
1555+
types: types,
1556+
},
1557+
bound_set: bound_set
15381558
});
15391559

15401560
// We're done if we don't see a '::', unless the mode required
@@ -1547,25 +1567,42 @@ impl<'a> Parser<'a> {
15471567
}
15481568
}
15491569

1550-
// Next, parse a colon and bounded type parameters, if applicable.
1551-
let bounds = if mode == LifetimeAndTypesAndBounds {
1552-
self.parse_optional_ty_param_bounds()
1553-
} else {
1554-
None
1555-
};
1556-
15571570
// Assemble the span.
15581571
let span = mk_sp(lo, self.last_span.hi);
15591572

1573+
// Assemble the path segments.
1574+
let mut path_segments = Vec::new();
1575+
let mut bounds = None;
1576+
let last_segment_index = segments.len() - 1;
1577+
for (i, segment_and_bounds) in segments.move_iter().enumerate() {
1578+
let PathSegmentAndBoundSet {
1579+
segment: segment,
1580+
bound_set: bound_set
1581+
} = segment_and_bounds;
1582+
path_segments.push(segment);
1583+
1584+
if bound_set.is_some() {
1585+
if i != last_segment_index {
1586+
self.span_err(span,
1587+
"type parameter bounds are allowed only \
1588+
before the last segment in a path")
1589+
}
1590+
1591+
bounds = bound_set
1592+
}
1593+
}
1594+
15601595
// Assemble the result.
1561-
PathAndBounds {
1596+
let path_and_bounds = PathAndBounds {
15621597
path: ast::Path {
15631598
span: span,
15641599
global: is_global,
1565-
segments: segments,
1600+
segments: path_segments,
15661601
},
15671602
bounds: bounds,
1568-
}
1603+
};
1604+
1605+
path_and_bounds
15691606
}
15701607

15711608
/// parses 0 or 1 lifetime

0 commit comments

Comments
 (0)