auto merge of #13001 : cmr/rust/unnamed-lifetime-nocapture, r=nikomatsakis
Closes #6751
This commit is contained in:
commit
25e523833e
@ -246,6 +246,8 @@ fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
|
||||
pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
|
||||
inputs: &[ty::t], output: ty::t,
|
||||
name: &str) -> ValueRef {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
|
||||
let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
|
||||
let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
|
||||
|
||||
@ -265,7 +267,16 @@ pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
|
||||
}
|
||||
}
|
||||
},
|
||||
// When a reference in an argument has no named lifetime, it's
|
||||
// impossible for that reference to escape this function(ie, be
|
||||
// returned).
|
||||
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
|
||||
debug!("marking argument of {} as nocapture because of anonymous lifetime", name);
|
||||
unsafe {
|
||||
llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
// For non-immediate arguments the callee gets its own copy of
|
||||
// the value on the stack, so there are no aliases
|
||||
|
@ -20,7 +20,7 @@ use std::slice;
|
||||
|
||||
use back::abi;
|
||||
use driver::session;
|
||||
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
|
||||
use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute, NoCaptureAttribute};
|
||||
use lib::llvm::llvm;
|
||||
use metadata::csearch;
|
||||
use middle::trans::base;
|
||||
@ -661,9 +661,15 @@ pub fn trans_call_inner<'a>(
|
||||
llargs.push(opt_llretslot.unwrap());
|
||||
}
|
||||
|
||||
// start at 1, because index 0 is the return value of the llvm func
|
||||
let mut first_arg_offset = 1;
|
||||
|
||||
// Push the environment (or a trait object's self).
|
||||
match (llenv, llself) {
|
||||
(Some(llenv), None) => llargs.push(llenv),
|
||||
(Some(llenv), None) => {
|
||||
first_arg_offset += 1;
|
||||
llargs.push(llenv)
|
||||
},
|
||||
(None, Some(llself)) => llargs.push(llself),
|
||||
_ => {}
|
||||
}
|
||||
@ -682,6 +688,11 @@ pub fn trans_call_inner<'a>(
|
||||
let mut attrs = Vec::new();
|
||||
if type_of::return_uses_outptr(ccx, ret_ty) {
|
||||
attrs.push((1, StructRetAttribute));
|
||||
// The outptr can be noalias and nocapture because it's entirely
|
||||
// invisible to the program.
|
||||
attrs.push((1, NoAliasAttribute));
|
||||
attrs.push((1, NoCaptureAttribute));
|
||||
first_arg_offset += 1;
|
||||
}
|
||||
|
||||
// The `noalias` attribute on the return value is useful to a
|
||||
@ -695,6 +706,30 @@ pub fn trans_call_inner<'a>(
|
||||
_ => {}
|
||||
}
|
||||
|
||||
debug!("trans_callee_inner: first_arg_offset={}", first_arg_offset);
|
||||
|
||||
for (idx, &t) in ty::ty_fn_args(callee_ty).iter().enumerate()
|
||||
.map(|(i, v)| (i+first_arg_offset, v)) {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
if !type_is_immediate(ccx, t) {
|
||||
// if it's not immediate, we have a program-invisible pointer,
|
||||
// which it can't possibly capture
|
||||
attrs.push((idx, NoCaptureAttribute));
|
||||
debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
let t_ = ty::get(t);
|
||||
match t_.sty {
|
||||
ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
|
||||
debug!("trans_callee_inner: argument {} nocapture because \
|
||||
of anonymous lifetime", idx);
|
||||
attrs.push((idx, NoCaptureAttribute));
|
||||
},
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the actual rust fn and update bcx/llresult.
|
||||
let (llret, b) = base::invoke(bcx,
|
||||
llfn,
|
||||
|
@ -28,6 +28,7 @@ fn silent_recurse() {
|
||||
fn loud_recurse() {
|
||||
println!("hello!");
|
||||
loud_recurse();
|
||||
black_box(()); // don't optimize this into a tail call. please.
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user