Skip to content

Commit 25e5238

Browse files
committed
auto merge of #13001 : cmr/rust/unnamed-lifetime-nocapture, r=nikomatsakis
Closes #6751
2 parents e560db7 + 5258e13 commit 25e5238

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

src/librustc/middle/trans/base.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ 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::{BrAnon, ReLateBound};
250+
249251
let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
250252
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
251253

@@ -265,7 +267,16 @@ pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
265267
unsafe {
266268
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
267269
}
268-
}
270+
},
271+
// When a reference in an argument has no named lifetime, it's
272+
// impossible for that reference to escape this function(ie, be
273+
// returned).
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

src/librustc/middle/trans/callee.rs

+37-2
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()
712+
.map(|(i, v)| (i+first_arg_offset, v)) {
713+
use middle::ty::{BrAnon, ReLateBound};
714+
if !type_is_immediate(ccx, t) {
715+
// if it's not immediate, we have a program-invisible pointer,
716+
// which it can't possibly capture
717+
attrs.push((idx, NoCaptureAttribute));
718+
debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx);
719+
continue;
720+
}
721+
722+
let t_ = ty::get(t);
723+
match t_.sty {
724+
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
725+
debug!("trans_callee_inner: argument {} nocapture because \
726+
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,

src/test/run-pass/out-of-stack.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ fn silent_recurse() {
2828
fn loud_recurse() {
2929
println!("hello!");
3030
loud_recurse();
31+
black_box(()); // don't optimize this into a tail call. please.
3132
}
3233

3334
fn main() {

0 commit comments

Comments
 (0)