Add syntax and representation for return-by-mutably-rooted-ref
This will be used in the near future to decide what can safely be done with the returned reference. Issue #918
This commit is contained in:
parent
1cabe37155
commit
93de2f0b74
@ -21,8 +21,6 @@ type str_def = fn(str) -> ast::def_id;
|
||||
type pstate =
|
||||
{data: @[u8], crate: int, mutable pos: uint, len: uint, tcx: ty::ctxt};
|
||||
|
||||
tag ty_or_bang { a_ty(ty::t); a_bang; }
|
||||
|
||||
fn peek(st: @pstate) -> u8 { ret st.data[st.pos]; }
|
||||
|
||||
fn next(st: @pstate) -> u8 {
|
||||
@ -54,10 +52,12 @@ fn parse_ty_data(data: @[u8], crate_num: int, pos: uint, len: uint,
|
||||
ret result;
|
||||
}
|
||||
|
||||
fn parse_ty_or_bang(st: @pstate, sd: str_def) -> ty_or_bang {
|
||||
fn parse_ret_ty(st: @pstate, sd: str_def) -> (ast::ret_style, ty::t) {
|
||||
alt peek(st) as char {
|
||||
'!' { next(st); ret a_bang; }
|
||||
_ { ret a_ty(parse_ty(st, sd)); }
|
||||
'!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) }
|
||||
'&' { next(st); (ast::return_ref(false), parse_ty(st, sd)) }
|
||||
'^' { next(st); (ast::return_ref(true), parse_ty(st, sd)) }
|
||||
_ { (ast::return_val, parse_ty(st, sd)) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,12 +387,8 @@ fn parse_ty_fn(st: @pstate, sd: str_def) ->
|
||||
}
|
||||
st.pos += 1u; // eat the ']'
|
||||
let cs = parse_constrs(st, sd);
|
||||
alt parse_ty_or_bang(st, sd) {
|
||||
a_bang. {
|
||||
ret {args: inputs, ty: ty::mk_bot(st.tcx), cf: ast::noreturn, cs: cs};
|
||||
}
|
||||
a_ty(t) { ret {args: inputs, ty: t, cf: ast::return_val, cs: cs}; }
|
||||
}
|
||||
let (ret_style, ret_ty) = parse_ret_ty(st, sd);
|
||||
ret {args: inputs, ty: ret_ty, cf: ret_style, cs: cs};
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,6 +220,10 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
|
||||
}
|
||||
alt cf {
|
||||
noreturn. { w.write_char('!'); }
|
||||
return_ref(mut) {
|
||||
w.write_char(mut ? '^' : '&');
|
||||
enc_ty(w, cx, out);
|
||||
}
|
||||
_ { enc_ty(w, cx, out); }
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], _sp: span,
|
||||
// Non capturing functions start out fresh.
|
||||
_ { [] }
|
||||
};
|
||||
if f.decl.cf == ast::return_ref && !is_none(f.body.node.expr) {
|
||||
if ast_util::ret_by_ref(f.decl.cf) && !is_none(f.body.node.expr) {
|
||||
// FIXME this will be easier to lift once have DPS
|
||||
cx.tcx.sess.span_err(option::get(f.body.node.expr).span,
|
||||
"reference-returning functions may not " +
|
||||
@ -118,8 +118,13 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
|
||||
check_assign(cx, dest, src, sc, v);
|
||||
}
|
||||
ast::expr_ret(oexpr) {
|
||||
if sc.ret_style == ast::return_ref && !is_none(oexpr) {
|
||||
check_ret_ref(*cx, sc, option::get(oexpr));
|
||||
if !is_none(oexpr) {
|
||||
alt sc.ret_style {
|
||||
ast::return_ref(mut) {
|
||||
check_ret_ref(*cx, sc, mut, option::get(oexpr));
|
||||
}
|
||||
_ {}
|
||||
}
|
||||
}
|
||||
handled = false;
|
||||
}
|
||||
@ -176,7 +181,7 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
|
||||
|
||||
fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
||||
let fty = ty::type_autoderef(cx.tcx, ty::expr_ty(cx.tcx, f));
|
||||
let ret_ref = ty::ty_fn_ret_style(cx.tcx, fty) == ast::return_ref;
|
||||
let ret_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(cx.tcx, fty));
|
||||
let arg_ts = ty::ty_fn_args(cx.tcx, fty);
|
||||
let mut_roots: [{arg: uint, node: node_id}] = [];
|
||||
let bindings = [];
|
||||
@ -266,7 +271,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
||||
ret bindings;
|
||||
}
|
||||
|
||||
fn check_ret_ref(cx: ctx, sc: scope, expr: @ast::expr) {
|
||||
fn check_ret_ref(cx: ctx, sc: scope, mut: bool, expr: @ast::expr) {
|
||||
let root = expr_root(cx.tcx, expr, false);
|
||||
let bad = none;
|
||||
let mut_field = mut_field(root.ds);
|
||||
@ -312,7 +317,7 @@ fn check_ret_ref(cx: ctx, sc: scope, expr: @ast::expr) {
|
||||
// FIXME allow references to constants and static items?
|
||||
_ { bad = some("non-local value"); }
|
||||
}
|
||||
if mut_field { bad = some("mutable field"); }
|
||||
if mut_field && !mut { bad = some("mutable field"); }
|
||||
alt bad {
|
||||
some(name) {
|
||||
cx.tcx.sess.span_err(expr.span, "can not return a reference " +
|
||||
|
@ -101,7 +101,7 @@ fn type_of_fn(cx: @crate_ctxt, sp: span, proto: ast::proto,
|
||||
// Given a function type and a count of ty params, construct an llvm type
|
||||
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
||||
ty_param_count: uint) -> TypeRef {
|
||||
let by_ref = ty::ty_fn_ret_style(cx.tcx, fty) == ast::return_ref;
|
||||
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(cx.tcx, fty));
|
||||
ret type_of_fn(cx, sp, ty::ty_fn_proto(cx.tcx, fty),
|
||||
false, by_ref, ty::ty_fn_args(cx.tcx, fty),
|
||||
ty::ty_fn_ret(cx.tcx, fty), ty_param_count);
|
||||
@ -2969,7 +2969,7 @@ fn trans_field(cx: @block_ctxt, sp: span, v: ValueRef, t0: ty::t,
|
||||
let v = GEP(r.bcx, vtbl, [C_int(0), C_int(ix as int)]);
|
||||
let tcx = bcx_tcx(cx);
|
||||
let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, methods[ix]);
|
||||
let ret_ref = ty::ty_fn_ret_style(tcx, fn_ty) == ast::return_ref;
|
||||
let ret_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_ty));
|
||||
let ll_fn_ty =
|
||||
type_of_fn(bcx_ccx(cx), sp, ty::ty_fn_proto(tcx, fn_ty),
|
||||
true, ret_ref, ty::ty_fn_args(tcx, fn_ty),
|
||||
@ -3532,7 +3532,7 @@ fn trans_args(cx: @block_ctxt, llenv: ValueRef, gen: option::t<generic_info>,
|
||||
let ccx = bcx_ccx(cx);
|
||||
let tcx = ccx.tcx;
|
||||
let bcx: @block_ctxt = cx;
|
||||
let by_ref = ty::ty_fn_ret_style(tcx, fn_ty) == ast::return_ref;
|
||||
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fn_ty));
|
||||
// Arg 0: Output pointer.
|
||||
|
||||
// FIXME: test case looks like
|
||||
@ -3629,7 +3629,8 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||
// with trans_call.
|
||||
let fn_expr_ty = ty::expr_ty(bcx_tcx(in_cx), f);
|
||||
let fn_ty = ty::type_autoderef(bcx_tcx(in_cx), fn_expr_ty);
|
||||
let by_ref = ty::ty_fn_ret_style(bcx_tcx(in_cx), fn_ty) == ast::return_ref;
|
||||
let by_ref = ast_util::ret_by_ref(ty::ty_fn_ret_style(bcx_tcx(in_cx),
|
||||
fn_ty));
|
||||
// Things that return by reference must put their arguments (FIXME only
|
||||
// the referenced arguments) into the outer scope, so that they are still
|
||||
// alive when the return value is used.
|
||||
@ -4391,7 +4392,7 @@ fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
||||
let t = ty::expr_ty(bcx_tcx(cx), x);
|
||||
let lv = trans_lval(cx, x);
|
||||
bcx = lv.res.bcx;
|
||||
if cx.fcx.ret_style == ast::return_ref {
|
||||
if ast_util::ret_by_ref(cx.fcx.ret_style) {
|
||||
assert lv.is_mem;
|
||||
Store(bcx, lv.res.val, cx.fcx.llretptr);
|
||||
} else {
|
||||
@ -5364,7 +5365,7 @@ fn decl_fn_and_pair_full(ccx: @crate_ctxt, sp: span, path: [str], _flav: str,
|
||||
alt ty::struct(ccx.tcx, node_type) {
|
||||
ty::ty_fn(proto, inputs, output, rs, _) {
|
||||
llfty = type_of_fn(ccx, sp, proto, false,
|
||||
rs == ast::return_ref, inputs, output,
|
||||
ast_util::ret_by_ref(rs), inputs, output,
|
||||
vec::len(ty_params));
|
||||
}
|
||||
_ { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); }
|
||||
|
@ -882,7 +882,7 @@ fn process_normal_mthd(cx: @local_ctxt, m: @ast::method, self_ty: ty::t,
|
||||
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.node.id)) {
|
||||
ty::ty_fn(proto, inputs, output, rs, _) {
|
||||
llfnty = type_of_fn(cx.ccx, m.span, proto, true,
|
||||
rs == ast::return_ref, inputs, output,
|
||||
ast_util::ret_by_ref(rs), inputs, output,
|
||||
vec::len(ty_params));
|
||||
}
|
||||
}
|
||||
@ -933,7 +933,7 @@ fn populate_self_stack(bcx: @block_ctxt, self_stack: ValueRef,
|
||||
|
||||
fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
|
||||
tps: [ast::ty_param]) -> TypeRef {
|
||||
type_of_fn(ccx, sp, m.proto, true, m.cf == ast::return_ref,
|
||||
type_of_fn(ccx, sp, m.proto, true, ast_util::ret_by_ref(m.cf),
|
||||
m.inputs, m.output, vec::len(tps))
|
||||
}
|
||||
|
||||
|
@ -2471,7 +2471,7 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
||||
alt s {
|
||||
ast::noreturn. { "non-returning" }
|
||||
ast::return_val. { "return-by-value" }
|
||||
ast::return_ref. { "return-by-reference" }
|
||||
ast::return_ref(_) { "return-by-reference" }
|
||||
}
|
||||
}
|
||||
ret to_str(actual) + " function found where " + to_str(expect) +
|
||||
|
@ -381,7 +381,7 @@ tag ret_style {
|
||||
noreturn; // functions with return type _|_ that always
|
||||
// raise an error or exit (i.e. never return to the caller)
|
||||
return_val; // everything else
|
||||
return_ref;
|
||||
return_ref(bool);
|
||||
}
|
||||
|
||||
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
||||
|
@ -213,6 +213,13 @@ fn ternary_to_if(e: @expr) -> @expr {
|
||||
}
|
||||
}
|
||||
|
||||
fn ret_by_ref(style: ret_style) -> bool {
|
||||
alt style {
|
||||
return_ref(_) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust
|
||||
// fill-column: 78;
|
||||
|
@ -445,7 +445,7 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
||||
} else {
|
||||
let style = ast::return_val;
|
||||
if eat(p, token::BINOP(token::AND)) {
|
||||
style = ast::return_ref;
|
||||
style = ast::return_ref(eat(p, token::NOT));
|
||||
};
|
||||
(style, parse_ty(p, false))
|
||||
}
|
||||
|
@ -1224,7 +1224,10 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl, constrs: [@ast::constr]) {
|
||||
if decl.output.node != ast::ty_nil {
|
||||
space_if_not_bol(s);
|
||||
word_space(s, "->");
|
||||
if decl.cf == ast::return_ref { word(s.s, "&"); }
|
||||
alt decl.cf {
|
||||
ast::return_ref(mut) { word(s.s, mut ? "&!" : "&"); }
|
||||
_ {}
|
||||
}
|
||||
print_type(s, decl.output);
|
||||
}
|
||||
}
|
||||
@ -1423,7 +1426,10 @@ fn print_ty_fn(s: ps, proto: ast::proto, id: option::t<ast::ident>,
|
||||
if cf == ast::noreturn {
|
||||
word_nbsp(s, "!")
|
||||
} else {
|
||||
if cf == ast::return_ref { word(s.s, "&"); }
|
||||
alt cf {
|
||||
ast::return_ref(mut) { word(s.s, mut ? "&!" : "&"); }
|
||||
_ {}
|
||||
}
|
||||
print_type(s, output);
|
||||
}
|
||||
end(s);
|
||||
|
@ -59,11 +59,13 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
||||
s += ")";
|
||||
if struct(cx, output) != ty_nil {
|
||||
s += " -> ";
|
||||
if cf == ast::noreturn {
|
||||
s += "!";
|
||||
} else {
|
||||
if cf == ast::return_ref { s += "&"; }
|
||||
alt cf {
|
||||
ast::noreturn. { s += "!"; }
|
||||
ast::return_ref(mut) {
|
||||
s += mut ? "&!" : "&";
|
||||
s += ty_to_str(cx, output);
|
||||
}
|
||||
ast::return_val. { s += ty_to_str(cx, output); }
|
||||
}
|
||||
}
|
||||
s += constrs_str(constrs);
|
||||
|
Loading…
Reference in New Issue
Block a user