about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-09-14 17:18:48 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-09-14 17:30:38 +0200
commit93de2f0b7498cbc6a304ba3cb80f5a3ea57b8bc7 (patch)
treedd42794a80d712ff07af81493bd12231924e3e21
parent1cabe37155bf83af04ce7814186fbef096a253cb (diff)
downloadrust-93de2f0b7498cbc6a304ba3cb80f5a3ea57b8bc7.tar.gz
rust-93de2f0b7498cbc6a304ba3cb80f5a3ea57b8bc7.zip
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
-rw-r--r--src/comp/metadata/tydecode.rs18
-rw-r--r--src/comp/metadata/tyencode.rs4
-rw-r--r--src/comp/middle/alias.rs17
-rw-r--r--src/comp/middle/trans.rs13
-rw-r--r--src/comp/middle/trans_objects.rs4
-rw-r--r--src/comp/middle/ty.rs2
-rw-r--r--src/comp/syntax/ast.rs2
-rw-r--r--src/comp/syntax/ast_util.rs7
-rw-r--r--src/comp/syntax/parse/parser.rs2
-rw-r--r--src/comp/syntax/print/pprust.rs10
-rw-r--r--src/comp/util/ppaux.rs10
11 files changed, 55 insertions, 34 deletions
diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs
index cc342fe4647..b4ea33a1277 100644
--- a/src/comp/metadata/tydecode.rs
+++ b/src/comp/metadata/tydecode.rs
@@ -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};
 }
 
 
diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs
index 5103fbd917d..234968cd97c 100644
--- a/src/comp/metadata/tyencode.rs
+++ b/src/comp/metadata/tyencode.rs
@@ -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); }
     }
 }
diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs
index ae71acdaa11..c8536ef2ddb 100644
--- a/src/comp/middle/alias.rs
+++ b/src/comp/middle/alias.rs
@@ -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 " +
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index fbdbe9f269a..ba495934387 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -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!"); }
diff --git a/src/comp/middle/trans_objects.rs b/src/comp/middle/trans_objects.rs
index 5f538c24eca..a74ee6ba9ed 100644
--- a/src/comp/middle/trans_objects.rs
+++ b/src/comp/middle/trans_objects.rs
@@ -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))
 }
 
diff --git a/src/comp/middle/ty.rs b/src/comp/middle/ty.rs
index dc9353dc2fd..e03a3c80a00 100644
--- a/src/comp/middle/ty.rs
+++ b/src/comp/middle/ty.rs
@@ -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) +
diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs
index 15d05cfe243..f064519cca3 100644
--- a/src/comp/syntax/ast.rs
+++ b/src/comp/syntax/ast.rs
@@ -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};
diff --git a/src/comp/syntax/ast_util.rs b/src/comp/syntax/ast_util.rs
index 1c11a56272e..b6c4eb9a929 100644
--- a/src/comp/syntax/ast_util.rs
+++ b/src/comp/syntax/ast_util.rs
@@ -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;
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index 8309afb85a2..543f2e65383 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -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))
         }
diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs
index beb22544fda..92ecceb7ad1 100644
--- a/src/comp/syntax/print/pprust.rs
+++ b/src/comp/syntax/print/pprust.rs
@@ -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);
diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs
index 3aa002c50fe..7e84c08a1d0 100644
--- a/src/comp/util/ppaux.rs
+++ b/src/comp/util/ppaux.rs
@@ -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);