Skip to content

Commit d6b3d65

Browse files
committed
Merge pull request #3857 from pcwalton/tuple-struct-ctors
rustc: Translate tuple struct constructors. r=brson
2 parents ce23a99 + 599b420 commit d6b3d65

File tree

13 files changed

+192
-48
lines changed

13 files changed

+192
-48
lines changed

src/libsyntax/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1480,7 +1480,7 @@ type struct_def = {
14801480
dtor: Option<class_dtor>,
14811481
/* ID of the constructor. This is only used for tuple- or enum-like
14821482
* structs. */
1483-
ctor_id: node_id
1483+
ctor_id: Option<node_id>
14841484
};
14851485

14861486
/*

src/libsyntax/ast_map.rs

+17
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ enum ast_node {
7474
// Destructor for a class
7575
node_dtor(~[ty_param], @class_dtor, def_id, @path),
7676
node_block(blk),
77+
node_struct_ctor(@struct_def, @item, @path)
7778
}
7879

7980
type map = std::map::HashMap<node_id, ast_node>;
@@ -284,6 +285,19 @@ fn map_struct_def(struct_def: @ast::struct_def, parent_node: ast_node,
284285
for vec::each(struct_def.methods) |m| {
285286
map_method(d_id, p, *m, cx);
286287
}
288+
// If this is a tuple-like struct, register the constructor.
289+
match struct_def.ctor_id {
290+
None => {}
291+
Some(ctor_id) => {
292+
match parent_node {
293+
node_item(item, _) => {
294+
cx.map.insert(ctor_id,
295+
node_struct_ctor(struct_def, item, p));
296+
}
297+
_ => fail ~"struct def parent wasn't an item"
298+
}
299+
}
300+
}
287301
}
288302

289303
fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
@@ -375,6 +389,9 @@ fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str {
375389
Some(node_block(_)) => {
376390
fmt!("block")
377391
}
392+
Some(node_struct_ctor(*)) => {
393+
fmt!("struct_ctor")
394+
}
378395
}
379396
}
380397
// Local Variables:

src/libsyntax/ast_util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,12 @@ fn view_path_id(p: @view_path) -> node_id {
589589
}
590590
}
591591

592+
/// Returns true if the given struct def is tuple-like; i.e. that its fields
593+
/// are unnamed.
594+
fn struct_def_is_tuple_like(struct_def: @ast::struct_def) -> bool {
595+
struct_def.ctor_id.is_some()
596+
}
597+
592598
// Local Variables:
593599
// mode: rust
594600
// fill-column: 78;

src/libsyntax/fold.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ fn fold_struct_def(struct_def: @ast::struct_def, fld: ast_fold)
281281
fields: vec::map(struct_def.fields, |f| fold_struct_field(*f, fld)),
282282
methods: vec::map(struct_def.methods, |m| fld.fold_method(*m)),
283283
dtor: dtor,
284-
ctor_id: fld.new_id(struct_def.ctor_id)
284+
ctor_id: option::map(&struct_def.ctor_id, |cid| fld.new_id(*cid))
285285
};
286286
}
287287

@@ -565,7 +565,7 @@ fn noop_fold_variant(v: variant_, fld: ast_fold) -> variant_ {
565565
methods: vec::map(struct_def.methods,
566566
|m| fld.fold_method(*m)),
567567
dtor: dtor,
568-
ctor_id: fld.new_id(struct_def.ctor_id)
568+
ctor_id: option::map(&struct_def.ctor_id, |c| fld.new_id(*c))
569569
})
570570
}
571571

src/libsyntax/parse/parser.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -2659,9 +2659,11 @@ impl Parser {
26592659
let mut fields: ~[@struct_field];
26602660
let mut methods: ~[@method] = ~[];
26612661
let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None;
2662+
let is_tuple_like;
26622663

26632664
if self.eat(token::LBRACE) {
26642665
// It's a record-like struct.
2666+
is_tuple_like = false;
26652667
fields = ~[];
26662668
while self.token != token::RBRACE {
26672669
match self.parse_class_item() {
@@ -2694,6 +2696,7 @@ impl Parser {
26942696
self.bump();
26952697
} else if self.token == token::LPAREN {
26962698
// It's a tuple-like struct.
2699+
is_tuple_like = true;
26972700
fields = do self.parse_unspanned_seq(token::LPAREN, token::RPAREN,
26982701
seq_sep_trailing_allowed
26992702
(token::COMMA)) |p| {
@@ -2708,6 +2711,7 @@ impl Parser {
27082711
self.expect(token::SEMI);
27092712
} else if self.eat(token::SEMI) {
27102713
// It's a unit-like struct.
2714+
is_tuple_like = true;
27112715
fields = ~[];
27122716
} else {
27132717
self.fatal(fmt!("expected `{`, `(`, or `;` after struct name \
@@ -2723,13 +2727,14 @@ impl Parser {
27232727
body: d_body},
27242728
span: d_s}};
27252729
let _ = self.get_id(); // XXX: Workaround for crazy bug.
2730+
let new_id = self.get_id();
27262731
(class_name,
27272732
item_class(@{
27282733
traits: traits,
27292734
fields: move fields,
27302735
methods: move methods,
27312736
dtor: actual_dtor,
2732-
ctor_id: self.get_id()
2737+
ctor_id: if is_tuple_like { Some(new_id) } else { None }
27332738
}, ty_params),
27342739
None)
27352740
}
@@ -3076,7 +3081,7 @@ impl Parser {
30763081
fields: move fields,
30773082
methods: move methods,
30783083
dtor: actual_dtor,
3079-
ctor_id: self.get_id()
3084+
ctor_id: Some(self.get_id())
30803085
};
30813086
}
30823087

src/libsyntax/parse/token.rs

+1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ mod special_idents {
311311
const static : ident = ident { repr: 31u };
312312
const intrinsic : ident = ident { repr: 32u };
313313
const clownshoes_foreign_mod: ident = ident { repr: 33 };
314+
const unnamed_field: ident = ident { repr: 34 };
314315
}
315316

316317
struct ident_interner {

src/rustc/middle/resolve.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1187,12 +1187,14 @@ impl Resolver {
11871187

11881188
// If this struct is tuple-like or enum-like, define a name
11891189
// in the value namespace.
1190-
if struct_def.fields.len() == 0 ||
1191-
struct_def.fields[0].node.kind == unnamed_field {
1192-
name_bindings.define_value(
1193-
privacy,
1194-
def_class(local_def(struct_def.ctor_id)),
1195-
sp);
1190+
match struct_def.ctor_id {
1191+
None => {}
1192+
Some(ctor_id) => {
1193+
name_bindings.define_value(
1194+
privacy,
1195+
def_class(local_def(ctor_id)),
1196+
sp);
1197+
}
11961198
}
11971199

11981200
// Record the def ID of this struct.

src/rustc/middle/trans/base.rs

+83-8
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,8 @@ fn trans_enum_variant(ccx: @crate_ctxt,
16481648
enum_id: ast::node_id,
16491649
variant: ast::variant,
16501650
args: ~[ast::variant_arg],
1651-
disr: int, is_degen: bool,
1651+
disr: int,
1652+
is_degen: bool,
16521653
param_substs: Option<param_substs>,
16531654
llfndecl: ValueRef) {
16541655
let _icx = ccx.insn_ctxt("trans_enum_variant");
@@ -1698,6 +1699,51 @@ fn trans_enum_variant(ccx: @crate_ctxt,
16981699
finish_fn(fcx, lltop);
16991700
}
17001701

1702+
// NB: In theory this should be merged with the function above. But the AST
1703+
// structures are completely different, so very little code would be shared.
1704+
fn trans_tuple_struct(ccx: @crate_ctxt,
1705+
fields: ~[@ast::struct_field],
1706+
ctor_id: ast::node_id,
1707+
param_substs: Option<param_substs>,
1708+
llfndecl: ValueRef) {
1709+
let _icx = ccx.insn_ctxt("trans_tuple_struct");
1710+
1711+
// Translate struct fields to function arguments.
1712+
let fn_args = do fields.map |field| {
1713+
{
1714+
mode: ast::expl(ast::by_copy),
1715+
ty: field.node.ty,
1716+
ident: special_idents::arg,
1717+
id: field.node.id
1718+
}
1719+
};
1720+
1721+
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, None,
1722+
param_substs, None);
1723+
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
1724+
1725+
let bcx = top_scope_block(fcx, None);
1726+
let lltop = bcx.llbb;
1727+
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
1728+
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
1729+
1730+
for fields.eachi |i, field| {
1731+
let lldestptr = GEPi(bcx, fcx.llretptr, [0, 0, i]);
1732+
let llarg = match fcx.llargs.get(field.node.id) {
1733+
local_mem(x) => x,
1734+
_ => {
1735+
ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \
1736+
local_mem")
1737+
}
1738+
};
1739+
let arg_ty = arg_tys[i].ty;
1740+
memmove_ty(bcx, lldestptr, llarg, arg_ty);
1741+
}
1742+
1743+
build_return(bcx);
1744+
finish_fn(fcx, lltop);
1745+
}
1746+
17011747
fn trans_class_dtor(ccx: @crate_ctxt, path: path,
17021748
body: ast::blk, dtor_id: ast::node_id,
17031749
psubsts: Option<param_substs>,
@@ -1835,15 +1881,27 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) {
18351881
fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
18361882
tps: ~[ast::ty_param], path: @ast_map::path,
18371883
ident: ast::ident, id: ast::node_id) {
1884+
// If there are type parameters, the destructor and constructor will be
1885+
// monomorphized, so we don't translate them here.
18381886
if tps.len() == 0u {
1839-
do option::iter(&struct_def.dtor) |dtor| {
1840-
trans_class_dtor(ccx, *path, dtor.node.body,
1841-
dtor.node.id, None, None, local_def(id));
1842-
};
1887+
// Translate the destructor.
1888+
do option::iter(&struct_def.dtor) |dtor| {
1889+
trans_class_dtor(ccx, *path, dtor.node.body,
1890+
dtor.node.id, None, None, local_def(id));
1891+
};
1892+
1893+
// If this is a tuple-like struct, translate the constructor.
1894+
match struct_def.ctor_id {
1895+
None => {}
1896+
Some(ctor_id) => {
1897+
let llfndecl = get_item_val(ccx, ctor_id);
1898+
trans_tuple_struct(ccx, struct_def.fields, ctor_id, None,
1899+
llfndecl);
1900+
}
1901+
}
18431902
}
1844-
// If there are ty params, the ctor will get monomorphized
18451903

1846-
// Translate methods
1904+
// Translate methods.
18471905
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id);
18481906
}
18491907

@@ -2128,8 +2186,25 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
21282186
set_inline_hint(llfn);
21292187
llfn
21302188
}
2189+
2190+
ast_map::node_struct_ctor(struct_def, struct_item, struct_path) => {
2191+
// Only register the constructor if this is a tuple-like struct.
2192+
match struct_def.ctor_id {
2193+
None => {
2194+
ccx.tcx.sess.bug(~"attempt to register a constructor of \
2195+
a non-tuple-like struct")
2196+
}
2197+
Some(ctor_id) => {
2198+
let llfn = register_fn(ccx, struct_item.span,
2199+
*struct_path, ctor_id);
2200+
set_inline_hint(llfn);
2201+
llfn
2202+
}
2203+
}
2204+
}
2205+
21312206
_ => {
2132-
ccx.sess.bug(~"get_item_val(): unexpected variant");
2207+
ccx.sess.bug(~"get_item_val(): unexpected variant")
21332208
}
21342209
};
21352210
if !(exprt || ccx.reachable.contains_key(id)) {

src/rustc/middle/trans/callee.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
9090
vid).args.len() > 0u;
9191
fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id))
9292
}
93+
ast::def_class(def_id) => {
94+
fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id))
95+
}
9396
ast::def_arg(*) |
9497
ast::def_local(*) |
9598
ast::def_binding(*) |
@@ -99,7 +102,7 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
99102
}
100103
ast::def_mod(*) | ast::def_foreign_mod(*) |
101104
ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
102-
ast::def_use(*) | ast::def_class(*) | ast::def_typaram_binder(*) |
105+
ast::def_use(*) | ast::def_typaram_binder(*) |
103106
ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => {
104107
bcx.tcx().sess.span_bug(
105108
ref_expr.span,

src/rustc/middle/trans/monomorphize.rs

+13
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ fn monomorphic_fn(ccx: @crate_ctxt,
9696
ast_map::node_local(*) => {
9797
ccx.tcx.sess.bug(~"Can't monomorphize a local")
9898
}
99+
ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
99100
};
100101

101102
// Look up the impl type if we're translating a default method.
@@ -208,6 +209,18 @@ fn monomorphic_fn(ccx: @crate_ctxt,
208209
impl_did_opt.get());
209210
d
210211
}
212+
ast_map::node_struct_ctor(struct_def, _, _) => {
213+
let d = mk_lldecl();
214+
set_inline_hint(d);
215+
base::trans_tuple_struct(ccx,
216+
struct_def.fields,
217+
option::expect(struct_def.ctor_id,
218+
~"ast-mapped tuple struct \
219+
didn't have a ctor id"),
220+
psubsts,
221+
d);
222+
d
223+
}
211224

212225
// Ugh -- but this ensures any new variants won't be forgotten
213226
ast_map::node_expr(*) |

src/rustc/middle/ty.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,10 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path {
36303630
syntax::parse::token::special_idents::literally_dtor))
36313631
}
36323632

3633+
ast_map::node_struct_ctor(_, item, path) => {
3634+
vec::append_one(*path, ast_map::path_name(item.ident))
3635+
}
3636+
36333637
ast_map::node_stmt(*) | ast_map::node_expr(*) |
36343638
ast_map::node_arg(*) | ast_map::node_local(*) |
36353639
ast_map::node_export(*) | ast_map::node_block(*) => {
@@ -3874,7 +3878,13 @@ fn class_field_tys(fields: ~[@struct_field]) -> ~[field_ty] {
38743878
vis: visibility,
38753879
mutability: mutability});
38763880
}
3877-
unnamed_field => {}
3881+
unnamed_field => {
3882+
rslt.push({ident:
3883+
syntax::parse::token::special_idents::unnamed_field,
3884+
id: ast_util::local_def(field.node.id),
3885+
vis: ast::public,
3886+
mutability: ast::class_immutable});
3887+
}
38783888
}
38793889
}
38803890
rslt

0 commit comments

Comments
 (0)