diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index bcda838b2486c..d8785176e0818 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -74,6 +74,7 @@ enum ast_node { // Destructor for a class node_dtor(~[ty_param], @class_dtor, def_id, @path), node_block(blk), + node_ctor(@struct_def, @item, @path) } type map = std::map::HashMap; @@ -284,6 +285,17 @@ fn map_struct_def(struct_def: @ast::struct_def, parent_node: ast_node, for vec::each(struct_def.methods) |m| { map_method(d_id, p, *m, cx); } + // If this is a tuple-like struct, register the constructor. + if struct_def.fields.len() == 0 || + struct_def.fields[0].node.kind == ast::unnamed_field { + match parent_node { + node_item(item, path) => { + cx.map.insert(struct_def.ctor_id, + node_ctor(struct_def, item, p)); + } + _ => fail ~"struct def parent wasn't an item" + } + } } fn map_view_item(vi: @view_item, cx: ctx, _v: vt) { @@ -375,6 +387,9 @@ fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { Some(node_block(_)) => { fmt!("block") } + Some(node_ctor(*)) => { + fmt!("ctor") + } } } // Local Variables: diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5151fd1bac837..53c1ce1c7f535 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -311,6 +311,7 @@ mod special_idents { const static : ident = ident { repr: 31u }; const intrinsic : ident = ident { repr: 32u }; const clownshoes_foreign_mod: ident = ident { repr: 33 }; + const unnamed_field: ident = ident { repr: 34 }; } struct ident_interner { diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 3896fdf0e7a06..770bf35d2f971 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -1648,7 +1648,8 @@ fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id, variant: ast::variant, args: ~[ast::variant_arg], - disr: int, is_degen: bool, + disr: int, + is_degen: bool, param_substs: Option, llfndecl: ValueRef) { let _icx = ccx.insn_ctxt("trans_enum_variant"); @@ -1698,6 +1699,52 @@ fn trans_enum_variant(ccx: @crate_ctxt, finish_fn(fcx, lltop); } +// NB: In theory this should be merged with the function above. But the AST +// structures are completely different, so very little code would be shared. +fn trans_tuple_struct(ccx: @crate_ctxt, + fields: ~[@ast::struct_field], + ctor_id: ast::node_id, + param_substs: Option, + llfndecl: ValueRef) { + let _icx = ccx.insn_ctxt("trans_tuple_struct"); + + // Translate struct fields to function arguments. + let fn_args = do fields.map |field| { + { + mode: ast::expl(ast::by_copy), + ty: field.node.ty, + ident: special_idents::arg, + id: field.node.id + } + }; + + let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, ctor_id, None, + param_substs, None); + let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args); + + let bcx = top_scope_block(fcx, None); + let lltop = bcx.llbb; + let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id)); + let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); + + for fields.eachi |i, field| { + let lldestptr = GEPi(bcx, fcx.llretptr, [0, 0, i]); + let llarg; + match fcx.llargs.get(field.node.id) { + local_mem(x) => llarg = x, + _ => { + ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \ + local_mem"); + } + } + let arg_ty = arg_tys[i].ty; + memmove_ty(bcx, lldestptr, llarg, arg_ty); + } + + build_return(bcx); + finish_fn(fcx, lltop); +} + fn trans_class_dtor(ccx: @crate_ctxt, path: path, body: ast::blk, dtor_id: ast::node_id, psubsts: Option, @@ -1835,15 +1882,25 @@ fn trans_item(ccx: @crate_ctxt, item: ast::item) { fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def, tps: ~[ast::ty_param], path: @ast_map::path, ident: ast::ident, id: ast::node_id) { + // If there are type parameters, the destructor and constructor will be + // monomorphized, so we don't translate them here. if tps.len() == 0u { - do option::iter(&struct_def.dtor) |dtor| { - trans_class_dtor(ccx, *path, dtor.node.body, - dtor.node.id, None, None, local_def(id)); - }; + // Translate the destructor. + do option::iter(&struct_def.dtor) |dtor| { + trans_class_dtor(ccx, *path, dtor.node.body, + dtor.node.id, None, None, local_def(id)); + }; + + // If this is a tuple-like struct, translate the constructor. + if struct_def.fields.len() == 0 || + struct_def.fields[0].node.kind == ast::unnamed_field { + let llfndecl = get_item_val(ccx, struct_def.ctor_id); + trans_tuple_struct(ccx, struct_def.fields, struct_def.ctor_id, + None, llfndecl); + } } - // If there are ty params, the ctor will get monomorphized - // Translate methods + // Translate methods. meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None, id); } @@ -2128,8 +2185,23 @@ fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef { set_inline_hint(llfn); llfn } + + ast_map::node_ctor(struct_def, struct_item, struct_path) => { + // Only register the constructor if this is a tuple-like struct. + if struct_def.fields.len() == 0 || + struct_def.fields[0].node.kind == ast::unnamed_field { + let llfn = register_fn(ccx, struct_item.span, *struct_path, + struct_def.ctor_id); + set_inline_hint(llfn); + llfn + } else { + ccx.tcx.sess.bug(~"attempt to register a constructor of a \ + non-tuple-like struct") + } + } + _ => { - ccx.sess.bug(~"get_item_val(): unexpected variant"); + ccx.sess.bug(~"get_item_val(): unexpected variant") } }; if !(exprt || ccx.reachable.contains_key(id)) { diff --git a/src/rustc/middle/trans/callee.rs b/src/rustc/middle/trans/callee.rs index 175381a7bd1ee..2c1e9b21c6d4f 100644 --- a/src/rustc/middle/trans/callee.rs +++ b/src/rustc/middle/trans/callee.rs @@ -90,6 +90,9 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee { vid).args.len() > 0u; fn_callee(bcx, trans_fn_ref(bcx, vid, ref_expr.id)) } + ast::def_class(def_id) => { + fn_callee(bcx, trans_fn_ref(bcx, def_id, ref_expr.id)) + } ast::def_arg(*) | ast::def_local(*) | ast::def_binding(*) | @@ -99,7 +102,7 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee { } ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | - ast::def_use(*) | ast::def_class(*) | ast::def_typaram_binder(*) | + ast::def_use(*) | ast::def_typaram_binder(*) | ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => { bcx.tcx().sess.span_bug( ref_expr.span, diff --git a/src/rustc/middle/trans/monomorphize.rs b/src/rustc/middle/trans/monomorphize.rs index c2f106f631b19..edea15ff662de 100644 --- a/src/rustc/middle/trans/monomorphize.rs +++ b/src/rustc/middle/trans/monomorphize.rs @@ -96,6 +96,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, ast_map::node_local(*) => { ccx.tcx.sess.bug(~"Can't monomorphize a local") } + ast_map::node_ctor(_, i, pt) => (pt, i.ident, i.span) }; // Look up the impl type if we're translating a default method. @@ -208,6 +209,13 @@ fn monomorphic_fn(ccx: @crate_ctxt, impl_did_opt.get()); d } + ast_map::node_ctor(struct_def, _, _) => { + let d = mk_lldecl(); + set_inline_hint(d); + base::trans_tuple_struct(ccx, struct_def.fields, struct_def.ctor_id, + psubsts, d); + d + } // Ugh -- but this ensures any new variants won't be forgotten ast_map::node_expr(*) | diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index e065fdfe0bc79..19ebba577a648 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -3571,6 +3571,10 @@ fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { syntax::parse::token::special_idents::literally_dtor)) } + ast_map::node_ctor(_, item, path) => { + vec::append_one(*path, ast_map::path_name(item.ident)) + } + ast_map::node_stmt(*) | ast_map::node_expr(*) | ast_map::node_arg(*) | ast_map::node_local(*) | ast_map::node_export(*) | ast_map::node_block(*) => { @@ -3815,7 +3819,13 @@ fn class_field_tys(fields: ~[@struct_field]) -> ~[field_ty] { vis: visibility, mutability: mutability}); } - unnamed_field => {} + unnamed_field => { + rslt.push({ident: + syntax::parse::token::special_idents::unnamed_field, + id: ast_util::local_def(field.node.id), + vis: ast::public, + mutability: ast::class_immutable}); + } } } rslt diff --git a/src/test/run-pass/tuple-struct-construct.rs b/src/test/run-pass/tuple-struct-construct.rs new file mode 100644 index 0000000000000..3d2630e7a5cac --- /dev/null +++ b/src/test/run-pass/tuple-struct-construct.rs @@ -0,0 +1,7 @@ +struct Foo(int, int); + +fn main() { + let x = Foo(1, 2); + io::println(fmt!("%?", x)); +} +