Skip to content

Commit 40f193f

Browse files
committed
---
yaml --- r: 12156 b: refs/heads/master c: edb747c h: refs/heads/master v: v3
1 parent 6d5d66f commit 40f193f

File tree

16 files changed

+188
-41
lines changed

16 files changed

+188
-41
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: c9102ee7a1e9c01e9befca44a0c0cb474fff89b4
2+
refs/heads/master: edb747ceedcfec2eb9f698b0e11b7e94d9174f33
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 4a81779abd786ff22d71434c6d9a5917ea4cdfff
55
refs/heads/try: 2898dcc5d97da9427ac367542382b6239d9c0bbf

trunk/src/rustc/metadata/common.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const tag_path_len: uint = 0x41u;
7878
const tag_path_elt_mod: uint = 0x42u;
7979
const tag_path_elt_name: uint = 0x43u;
8080
const tag_item_field: uint = 0x44u;
81+
const tag_class_mut: uint = 0x45u;
8182

8283
// used to encode crate_ctxt side tables
8384
enum astencode_tag { // Reserves 0x50 -- 0x6f

trunk/src/rustc/metadata/decoder.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ fn class_member_id(d: ebml::doc, cdata: cmd) -> ast::def_id {
118118
ret translate_def_id(cdata, parse_def_id(ebml::doc_data(tagdoc)));
119119
}
120120

121+
fn field_mutability(d: ebml::doc) -> ast::class_mutability {
122+
// Use maybe_get_doc in case it's a method
123+
option::maybe(ebml::maybe_get_doc(d, tag_class_mut),
124+
ast::class_immutable,
125+
{|d|
126+
alt ebml::doc_as_u8(d) as char {
127+
'm' { ast::class_mutable }
128+
_ { ast::class_immutable }
129+
}
130+
})
131+
}
132+
121133
fn variant_disr_val(d: ebml::doc) -> option<int> {
122134
option::chain(ebml::maybe_get_doc(d, tag_disr_val)) {|val_doc|
123135
int::parse_buf(ebml::doc_data(val_doc), 10u)
@@ -435,9 +447,9 @@ fn get_class_members(cdata: cmd, id: ast::node_id,
435447
if p(f) {
436448
let name = item_name(an_item);
437449
let did = class_member_id(an_item, cdata);
450+
let mt = field_mutability(an_item);
438451
result += [{ident: name, id: did, privacy:
439-
// This won't work for methods, argh
440-
family_to_privacy(f)}];
452+
family_to_privacy(f), mutability: mt}];
441453
}
442454
}
443455
result

trunk/src/rustc/metadata/encoder.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ fn encode_named_def_id(ebml_w: ebml::writer, name: str, id: def_id) {
4747
}
4848
}
4949

50+
fn encode_mutability(ebml_w: ebml::writer, mt: class_mutability) {
51+
ebml_w.wr_tag(tag_class_mut) {||
52+
ebml_w.writer.write([alt mt { class_immutable { 'i' }
53+
class_mutable { 'm' } } as u8]);
54+
}
55+
}
56+
5057
type entry<T> = {val: T, pos: uint};
5158

5259
fn encode_enum_variant_paths(ebml_w: ebml::writer, variants: [variant],
@@ -370,15 +377,15 @@ fn encode_info_for_class(ecx: @encode_ctxt, ebml_w: ebml::writer,
370377
/* We encode both private and public fields -- need to include
371378
private fields to get the offsets right */
372379
alt ci.node.decl {
373-
instance_var(nm, _, _, id) {
380+
instance_var(nm, _, mt, id) {
374381
*index += [{val: id, pos: ebml_w.writer.tell()}];
375382
ebml_w.start_tag(tag_items_data_item);
376383
#debug("encode_info_for_class: doing %s %d", nm, id);
377384
encode_privacy(ebml_w, ci.node.privacy);
378385
encode_name(ebml_w, nm);
379386
encode_path(ebml_w, path, ast_map::path_name(nm));
380387
encode_type(ecx, ebml_w, node_id_to_type(tcx, id));
381-
/* TODO: mutability */
388+
encode_mutability(ebml_w, mt);
382389
encode_def_id(ebml_w, local_def(id));
383390
ebml_w.end_tag();
384391
}

trunk/src/rustc/middle/mutbl.rs

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
5757
}
5858
}
5959
}
60+
ty::ty_class(did, _) {
61+
util::common::log_expr(*ex);
62+
for fld: ty::field_ty in ty::lookup_class_fields(tcx, did) {
63+
#debug("%s %?", fld.ident, fld.mutability);
64+
if str::eq(ident, fld.ident) {
65+
is_mutbl = fld.mutability == class_mutable;
66+
}
67+
break;
68+
}
69+
}
6070
_ {}
6171
}
6272
ds += [@{mutbl: is_mutbl, kind: field, outer_t: auto_unbox.t}];
@@ -114,14 +124,17 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
114124
// Actual mutbl-checking pass
115125

116126
type mutbl_map = std::map::hashmap<node_id, ()>;
117-
type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map};
127+
// Keep track of whether we're inside a ctor, so as to
128+
// allow mutating immutable fields in the same class
129+
type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map, in_ctor: bool};
118130

119131
fn check_crate(tcx: ty::ctxt, crate: @crate) -> mutbl_map {
120-
let cx = @{tcx: tcx, mutbl_map: std::map::int_hash()};
121-
let v = @{visit_expr: bind visit_expr(cx, _, _, _),
122-
visit_decl: bind visit_decl(cx, _, _, _)
132+
let cx = @{tcx: tcx, mutbl_map: std::map::int_hash(), in_ctor: false};
133+
let v = @{visit_expr: visit_expr,
134+
visit_decl: visit_decl,
135+
visit_item: visit_item
123136
with *visit::default_visitor()};
124-
visit::visit_crate(*crate, (), visit::mk_vt(v));
137+
visit::visit_crate(*crate, cx, visit::mk_vt(v));
125138
ret cx.mutbl_map;
126139
}
127140

@@ -135,8 +148,8 @@ fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) {
135148
});
136149
}
137150

138-
fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
139-
visit::visit_decl(d, e, v);
151+
fn visit_decl(d: @decl, &&cx: @ctx, v: visit::vt<@ctx>) {
152+
visit::visit_decl(d, cx, v);
140153
alt d.node {
141154
decl_local(locs) {
142155
for loc in locs {
@@ -152,7 +165,7 @@ fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
152165
}
153166
}
154167

155-
fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
168+
fn visit_expr(ex: @expr, &&cx: @ctx, v: visit::vt<@ctx>) {
156169
alt ex.node {
157170
expr_call(f, args, _) { check_call(cx, f, args); }
158171
expr_bind(f, args) { check_bind(cx, f, args); }
@@ -179,7 +192,22 @@ fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
179192
}
180193
_ { }
181194
}
182-
visit::visit_expr(ex, e, v);
195+
visit::visit_expr(ex, cx, v);
196+
}
197+
198+
fn visit_item(item: @item, &&cx: @ctx, v: visit::vt<@ctx>) {
199+
alt item.node {
200+
item_class(tps, items, ctor) {
201+
v.visit_ty_params(tps, cx, v);
202+
vec::map::<@class_item, ()>(items,
203+
{|i| v.visit_class_item(i.span,
204+
i.node.privacy, i.node.decl, cx, v); });
205+
v.visit_fn(visit::fk_ctor(item.ident, tps), ctor.node.dec,
206+
ctor.node.body, ctor.span, ctor.node.id,
207+
@{in_ctor: true with *cx}, v);
208+
}
209+
_ { visit::visit_item(item, cx, v); }
210+
}
183211
}
184212

185213
fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
@@ -277,7 +305,7 @@ fn check_bind(cx: @ctx, f: @expr, args: [option<@expr>]) {
277305
fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> {
278306
alt def {
279307
def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
280-
def_use(_) {
308+
def_use(_) | def_class_method(_,_) {
281309
some("static item")
282310
}
283311
def_arg(_, m) {
@@ -310,6 +338,18 @@ fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> {
310338
}
311339

312340
def_binding(_) { some("binding") }
341+
def_class_field(parent,fld) {
342+
if !cx.in_ctor {
343+
/* Enforce mutability *unless* we're inside a ctor */
344+
alt ty::lookup_class_field(cx.tcx, parent, fld).mutability {
345+
class_mutable { none }
346+
class_immutable { some("immutable class field") }
347+
}
348+
}
349+
else {
350+
none
351+
}
352+
}
313353
_ { none }
314354
}
315355
}

trunk/src/rustc/middle/trans/base.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,11 +2271,7 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
22712271
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
22722272
base expr has non-record type"); }
22732273
};
2274-
let ix = alt ty::field_idx(field, fields) {
2275-
none { bcx.tcx().sess.span_bug(sp, #fmt("trans_rec_field:\
2276-
base expr doesn't appear to have a field named %s", field));}
2277-
some(i) { i }
2278-
};
2274+
let ix = field_idx_strict(bcx.tcx(), sp, field, fields);
22792275
let val = GEPi(bcx, val, [0, ix as int]);
22802276
ret {bcx: bcx, val: val, kind: owned};
22812277
}
@@ -3666,7 +3662,7 @@ fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block {
36663662
// trans_block_cleanups: Go through all the cleanups attached to this
36673663
// block and execute them.
36683664
//
3669-
// When translating a block that introdces new variables during its scope, we
3665+
// When translating a block that introduces new variables during its scope, we
36703666
// need to make sure those variables go out of scope when the block ends. We
36713667
// do that by running a 'cleanup' function for each variable.
36723668
// trans_block_cleanups runs all the cleanup functions for the block.
@@ -4344,10 +4340,24 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
43444340
// wouldn't make sense
43454341
// So we initialize it here
43464342
let selfptr = alloc_ty(bcx_top, rslt_ty);
4343+
// initialize fields to zero
4344+
let fields = ty::class_items_as_fields(bcx_top.tcx(),
4345+
local_def(item.id));
4346+
let mut bcx = bcx_top;
4347+
// Initialize fields to zero so init assignments can validly
4348+
// drop their LHS
4349+
for field in fields {
4350+
let ix = field_idx_strict(bcx.tcx(), ctor.span, field.ident,
4351+
fields);
4352+
bcx = zero_alloca(bcx, GEPi(bcx, selfptr, [0, ix]),
4353+
field.mt.ty);
4354+
}
4355+
4356+
// note we don't want to take *or* drop self.
43474357
fcx.llself = some({v: selfptr, t: rslt_ty});
43484358

43494359
// Translate the body of the ctor
4350-
let mut bcx = trans_block(bcx_top, ctor.node.body, ignore);
4360+
bcx = trans_block(bcx_top, ctor.node.body, ignore);
43514361
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
43524362
// Generate the return expression
43534363
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,

trunk/src/rustc/middle/trans/common.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,16 @@ fn node_id_type_params(bcx: block, id: ast::node_id) -> [ty::t] {
884884
}
885885
}
886886

887+
fn field_idx_strict(cx: ty::ctxt, sp: span, ident: ast::ident,
888+
fields: [ty::field])
889+
-> int {
890+
alt ty::field_idx(ident, fields) {
891+
none { cx.sess.span_bug(sp, #fmt("base expr doesn't appear to \
892+
have a field named %s", ident)); }
893+
some(i) { i as int }
894+
}
895+
}
896+
887897
//
888898
// Local Variables:
889899
// mode: rust

trunk/src/rustc/middle/trans/shape.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ const shape_stack_fn: u8 = 26u8;
5757
const shape_bare_fn: u8 = 27u8;
5858
const shape_tydesc: u8 = 28u8;
5959
const shape_send_tydesc: u8 = 29u8;
60-
const shape_class: u8 = 30u8;
6160
const shape_rptr: u8 = 31u8;
6261

6362
fn hash_res_info(ri: res_info) -> uint {
@@ -370,7 +369,15 @@ fn shape_of(ccx: @crate_ctxt, t: ty::t, ty_param_map: [uint]) -> [u8] {
370369
s
371370
}
372371
ty::ty_iface(_, _) { [shape_box_fn] }
373-
ty::ty_class(_, _) { [shape_class] }
372+
ty::ty_class(did, _) {
373+
// same as records
374+
let mut s = [shape_struct], sub = [];
375+
for f:field in ty::class_items_as_fields(ccx.tcx, did) {
376+
sub += shape_of(ccx, f.mt.ty, ty_param_map);
377+
}
378+
add_substr(s, sub);
379+
s
380+
}
374381
ty::ty_rptr(_, tm) {
375382
let mut s = [shape_rptr];
376383
add_substr(s, shape_of(ccx, tm.ty, ty_param_map));

trunk/src/rustc/middle/ty.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export fm_var, fm_general, fm_rptr;
4141
export get_element_type;
4242
export is_binopable;
4343
export is_pred_ty;
44-
export lookup_class_fields;
44+
export lookup_class_field, lookup_class_fields;
4545
export lookup_class_method_by_name;
4646
export lookup_field_type;
4747
export lookup_item_type;
@@ -164,7 +164,8 @@ type mt = {ty: t, mutbl: ast::mutability};
164164
type field_ty = {
165165
ident: ident,
166166
id: def_id,
167-
privacy: ast::privacy
167+
privacy: ast::privacy,
168+
mutability: ast::class_mutability
168169
};
169170

170171
// Contains information needed to resolve types and (in the future) look up
@@ -864,6 +865,12 @@ fn type_needs_drop(cx: ctxt, ty: t) -> bool {
864865
for f in flds { if type_needs_drop(cx, f.mt.ty) { accum = true; } }
865866
accum
866867
}
868+
ty_class(did,_) {
869+
for f in ty::class_items_as_fields(cx, did)
870+
{ if type_needs_drop(cx, f.mt.ty) { accum = true; } }
871+
accum
872+
}
873+
867874
ty_tup(elts) {
868875
for m in elts { if type_needs_drop(cx, m) { accum = true; } }
869876
accum
@@ -1956,11 +1963,6 @@ fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty {
19561963
// Look up a field ID, whether or not it's local
19571964
fn lookup_field_type(tcx: ctxt, class_id: def_id, id: def_id) -> ty::t {
19581965
if id.crate == ast::local_crate {
1959-
/*
1960-
alt items.find(tcx.items, id.node) {
1961-
some(ast_map::node_item({node: item_class(_,items,
1962-
}
1963-
*/
19641966
node_id_to_type(tcx, id.node)
19651967
}
19661968
else {
@@ -1999,6 +2001,15 @@ fn lookup_class_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
19992001
}
20002002
}
20012003

2004+
fn lookup_class_field(cx: ctxt, parent: ast::def_id, field_id: ast::def_id)
2005+
-> field_ty {
2006+
alt vec::find(lookup_class_fields(cx, parent))
2007+
{|f| f.id.node == field_id.node} {
2008+
some(t) { t }
2009+
none { cx.sess.bug("class ID not found in parent's fields"); }
2010+
}
2011+
}
2012+
20022013
fn lookup_public_fields(cx: ctxt, did: ast::def_id) -> [field_ty] {
20032014
vec::filter(lookup_class_fields(cx, did), is_public)
20042015
}
@@ -2050,9 +2061,9 @@ fn class_field_tys(items: [@class_item]) -> [field_ty] {
20502061
let mut rslt = [];
20512062
for it in items {
20522063
alt it.node.decl {
2053-
instance_var(nm, _, _, id) {
2064+
instance_var(nm, _, cm, id) {
20542065
rslt += [{ident: nm, id: ast_util::local_def(id),
2055-
privacy: it.node.privacy}];
2066+
privacy: it.node.privacy, mutability: cm}];
20562067
}
20572068
class_method(_) {
20582069
}

trunk/src/rustc/syntax/parse/parser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,8 +1684,8 @@ fn parse_let(p: parser) -> @ast::decl {
16841684
fn parse_instance_var(p:parser) -> (ast::class_member, codemap::span) {
16851685
let mut is_mutbl = ast::class_immutable;
16861686
let lo = p.span.lo;
1687-
if eat_word(p, "mut") {
1688-
is_mutbl = ast::class_mutable;
1687+
if eat_word(p, "mut") || eat_word(p, "mutable") {
1688+
is_mutbl = ast::class_mutable;
16891689
}
16901690
if !is_plain_ident(p) {
16911691
p.fatal("expecting ident");

trunk/src/test/auxiliary/cci_class_4.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ class cat {
1212
}
1313
}
1414

15-
let how_hungry : int;
15+
let mutable how_hungry : int;
16+
let name : str;
1617

17-
new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
18+
new(in_x : uint, in_y : int, in_name: str)
19+
{ meows = in_x; how_hungry = in_y; name = in_name; }
1820

1921
fn speak() { meow(); }
2022

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// error-pattern:assigning to immutable class field
2+
class cat {
3+
priv {
4+
let mutable meows : uint;
5+
}
6+
7+
let how_hungry : int;
8+
9+
fn eat() {
10+
how_hungry -= 5;
11+
}
12+
13+
new(in_x : uint, in_y : int) { meows = in_x; how_hungry = in_y; }
14+
}
15+
16+
fn main() {
17+
let nyan : cat = cat(52u, 99);
18+
nyan.eat();
19+
}

0 commit comments

Comments
 (0)