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
11 changed files with 55 additions and 34 deletions
|
@ -21,8 +21,6 @@ type str_def = fn(str) -> ast::def_id;
|
||||||
type pstate =
|
type pstate =
|
||||||
{data: @[u8], crate: int, mutable pos: uint, len: uint, tcx: ty::ctxt};
|
{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 peek(st: @pstate) -> u8 { ret st.data[st.pos]; }
|
||||||
|
|
||||||
fn next(st: @pstate) -> u8 {
|
fn next(st: @pstate) -> u8 {
|
||||||
|
@ -54,10 +52,12 @@ fn parse_ty_data(data: @[u8], crate_num: int, pos: uint, len: uint,
|
||||||
ret result;
|
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 {
|
alt peek(st) as char {
|
||||||
'!' { next(st); ret a_bang; }
|
'!' { next(st); (ast::noreturn, ty::mk_bot(st.tcx)) }
|
||||||
_ { ret a_ty(parse_ty(st, sd)); }
|
'&' { 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 ']'
|
st.pos += 1u; // eat the ']'
|
||||||
let cs = parse_constrs(st, sd);
|
let cs = parse_constrs(st, sd);
|
||||||
alt parse_ty_or_bang(st, sd) {
|
let (ret_style, ret_ty) = parse_ret_ty(st, sd);
|
||||||
a_bang. {
|
ret {args: inputs, ty: ret_ty, cf: ret_style, cs: cs};
|
||||||
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}; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,10 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
|
||||||
}
|
}
|
||||||
alt cf {
|
alt cf {
|
||||||
noreturn. { w.write_char('!'); }
|
noreturn. { w.write_char('!'); }
|
||||||
|
return_ref(mut) {
|
||||||
|
w.write_char(mut ? '^' : '&');
|
||||||
|
enc_ty(w, cx, out);
|
||||||
|
}
|
||||||
_ { 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.
|
// 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
|
// FIXME this will be easier to lift once have DPS
|
||||||
cx.tcx.sess.span_err(option::get(f.body.node.expr).span,
|
cx.tcx.sess.span_err(option::get(f.body.node.expr).span,
|
||||||
"reference-returning functions may not " +
|
"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);
|
check_assign(cx, dest, src, sc, v);
|
||||||
}
|
}
|
||||||
ast::expr_ret(oexpr) {
|
ast::expr_ret(oexpr) {
|
||||||
if sc.ret_style == ast::return_ref && !is_none(oexpr) {
|
if !is_none(oexpr) {
|
||||||
check_ret_ref(*cx, sc, option::get(oexpr));
|
alt sc.ret_style {
|
||||||
|
ast::return_ref(mut) {
|
||||||
|
check_ret_ref(*cx, sc, mut, option::get(oexpr));
|
||||||
|
}
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
handled = false;
|
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] {
|
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 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 arg_ts = ty::ty_fn_args(cx.tcx, fty);
|
||||||
let mut_roots: [{arg: uint, node: node_id}] = [];
|
let mut_roots: [{arg: uint, node: node_id}] = [];
|
||||||
let bindings = [];
|
let bindings = [];
|
||||||
|
@ -266,7 +271,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
||||||
ret bindings;
|
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 root = expr_root(cx.tcx, expr, false);
|
||||||
let bad = none;
|
let bad = none;
|
||||||
let mut_field = mut_field(root.ds);
|
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?
|
// FIXME allow references to constants and static items?
|
||||||
_ { bad = some("non-local value"); }
|
_ { bad = some("non-local value"); }
|
||||||
}
|
}
|
||||||
if mut_field { bad = some("mutable field"); }
|
if mut_field && !mut { bad = some("mutable field"); }
|
||||||
alt bad {
|
alt bad {
|
||||||
some(name) {
|
some(name) {
|
||||||
cx.tcx.sess.span_err(expr.span, "can not return a reference " +
|
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
|
// 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,
|
fn type_of_fn_from_ty(cx: @crate_ctxt, sp: span, fty: ty::t,
|
||||||
ty_param_count: uint) -> TypeRef {
|
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),
|
ret type_of_fn(cx, sp, ty::ty_fn_proto(cx.tcx, fty),
|
||||||
false, by_ref, ty::ty_fn_args(cx.tcx, fty),
|
false, by_ref, ty::ty_fn_args(cx.tcx, fty),
|
||||||
ty::ty_fn_ret(cx.tcx, fty), ty_param_count);
|
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 v = GEP(r.bcx, vtbl, [C_int(0), C_int(ix as int)]);
|
||||||
let tcx = bcx_tcx(cx);
|
let tcx = bcx_tcx(cx);
|
||||||
let fn_ty: ty::t = ty::method_ty_to_fn_ty(tcx, methods[ix]);
|
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 =
|
let ll_fn_ty =
|
||||||
type_of_fn(bcx_ccx(cx), sp, ty::ty_fn_proto(tcx, 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),
|
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 ccx = bcx_ccx(cx);
|
||||||
let tcx = ccx.tcx;
|
let tcx = ccx.tcx;
|
||||||
let bcx: @block_ctxt = cx;
|
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.
|
// Arg 0: Output pointer.
|
||||||
|
|
||||||
// FIXME: test case looks like
|
// FIXME: test case looks like
|
||||||
|
@ -3629,7 +3629,8 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
|
||||||
// with trans_call.
|
// with trans_call.
|
||||||
let fn_expr_ty = ty::expr_ty(bcx_tcx(in_cx), f);
|
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 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
|
// Things that return by reference must put their arguments (FIXME only
|
||||||
// the referenced arguments) into the outer scope, so that they are still
|
// the referenced arguments) into the outer scope, so that they are still
|
||||||
// alive when the return value is used.
|
// 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 t = ty::expr_ty(bcx_tcx(cx), x);
|
||||||
let lv = trans_lval(cx, x);
|
let lv = trans_lval(cx, x);
|
||||||
bcx = lv.res.bcx;
|
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;
|
assert lv.is_mem;
|
||||||
Store(bcx, lv.res.val, cx.fcx.llretptr);
|
Store(bcx, lv.res.val, cx.fcx.llretptr);
|
||||||
} else {
|
} 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) {
|
alt ty::struct(ccx.tcx, node_type) {
|
||||||
ty::ty_fn(proto, inputs, output, rs, _) {
|
ty::ty_fn(proto, inputs, output, rs, _) {
|
||||||
llfty = type_of_fn(ccx, sp, proto, false,
|
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));
|
vec::len(ty_params));
|
||||||
}
|
}
|
||||||
_ { ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!"); }
|
_ { 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)) {
|
alt ty::struct(cx.ccx.tcx, node_id_type(cx.ccx, m.node.id)) {
|
||||||
ty::ty_fn(proto, inputs, output, rs, _) {
|
ty::ty_fn(proto, inputs, output, rs, _) {
|
||||||
llfnty = type_of_fn(cx.ccx, m.span, proto, true,
|
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));
|
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,
|
fn type_of_meth(ccx: @crate_ctxt, sp: span, m: @ty::method,
|
||||||
tps: [ast::ty_param]) -> TypeRef {
|
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))
|
m.inputs, m.output, vec::len(tps))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2471,7 +2471,7 @@ fn type_err_to_str(err: ty::type_err) -> str {
|
||||||
alt s {
|
alt s {
|
||||||
ast::noreturn. { "non-returning" }
|
ast::noreturn. { "non-returning" }
|
||||||
ast::return_val. { "return-by-value" }
|
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) +
|
ret to_str(actual) + " function found where " + to_str(expect) +
|
||||||
|
|
|
@ -381,7 +381,7 @@ tag ret_style {
|
||||||
noreturn; // functions with return type _|_ that always
|
noreturn; // functions with return type _|_ that always
|
||||||
// raise an error or exit (i.e. never return to the caller)
|
// raise an error or exit (i.e. never return to the caller)
|
||||||
return_val; // everything else
|
return_val; // everything else
|
||||||
return_ref;
|
return_ref(bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
type _fn = {decl: fn_decl, proto: proto, body: blk};
|
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:
|
// Local Variables:
|
||||||
// mode: rust
|
// mode: rust
|
||||||
// fill-column: 78;
|
// fill-column: 78;
|
||||||
|
|
|
@ -445,7 +445,7 @@ fn parse_ret_ty(p: parser) -> (ast::ret_style, @ast::ty) {
|
||||||
} else {
|
} else {
|
||||||
let style = ast::return_val;
|
let style = ast::return_val;
|
||||||
if eat(p, token::BINOP(token::AND)) {
|
if eat(p, token::BINOP(token::AND)) {
|
||||||
style = ast::return_ref;
|
style = ast::return_ref(eat(p, token::NOT));
|
||||||
};
|
};
|
||||||
(style, parse_ty(p, false))
|
(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 {
|
if decl.output.node != ast::ty_nil {
|
||||||
space_if_not_bol(s);
|
space_if_not_bol(s);
|
||||||
word_space(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);
|
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 {
|
if cf == ast::noreturn {
|
||||||
word_nbsp(s, "!")
|
word_nbsp(s, "!")
|
||||||
} else {
|
} else {
|
||||||
if cf == ast::return_ref { word(s.s, "&"); }
|
alt cf {
|
||||||
|
ast::return_ref(mut) { word(s.s, mut ? "&!" : "&"); }
|
||||||
|
_ {}
|
||||||
|
}
|
||||||
print_type(s, output);
|
print_type(s, output);
|
||||||
}
|
}
|
||||||
end(s);
|
end(s);
|
||||||
|
|
|
@ -59,11 +59,13 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
|
||||||
s += ")";
|
s += ")";
|
||||||
if struct(cx, output) != ty_nil {
|
if struct(cx, output) != ty_nil {
|
||||||
s += " -> ";
|
s += " -> ";
|
||||||
if cf == ast::noreturn {
|
alt cf {
|
||||||
s += "!";
|
ast::noreturn. { s += "!"; }
|
||||||
} else {
|
ast::return_ref(mut) {
|
||||||
if cf == ast::return_ref { s += "&"; }
|
s += mut ? "&!" : "&";
|
||||||
s += ty_to_str(cx, output);
|
s += ty_to_str(cx, output);
|
||||||
|
}
|
||||||
|
ast::return_val. { s += ty_to_str(cx, output); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += constrs_str(constrs);
|
s += constrs_str(constrs);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue