Skip to content

Commit df0ef52

Browse files
committed
rustc: Use LLVM named structs for enum types
1 parent 10120cc commit df0ef52

File tree

5 files changed

+207
-95
lines changed

5 files changed

+207
-95
lines changed

src/rustc/middle/trans/base.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2243,7 +2243,8 @@ fn trans_var(cx: block, def: ast::def, id: ast::node_id)-> lval_maybe_callee {
22432243
// Nullary variant.
22442244
let enum_ty = node_id_type(cx, id);
22452245
let llenumblob = alloc_ty(cx, enum_ty);
2246-
let llenumty = type_of_enum(ccx, tid, enum_ty);
2246+
// FIXME: This pointer cast probably isn't necessary
2247+
let llenumty = type_of(ccx, enum_ty);
22472248
let llenumptr = PointerCast(cx, llenumblob, T_ptr(llenumty));
22482249
let lldiscrimptr = GEPi(cx, llenumptr, [0, 0]);
22492250
let lldiscrim_gv = lookup_discriminant(ccx, vid);

src/rustc/middle/trans/type_of.rs

+136-75
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ import std::map::hashmap;
77

88
import ty::*;
99

10+
export type_of;
11+
export type_of_explicit_args;
12+
export type_of_fn_from_ty;
13+
export type_of_fn;
14+
1015
fn type_of_explicit_args(cx: @crate_ctxt, inputs: [ty::arg]) -> [TypeRef] {
1116
vec::map(inputs) {|arg|
1217
let arg_ty = arg.ty;
@@ -39,93 +44,149 @@ fn type_of_fn_from_ty(cx: @crate_ctxt, fty: ty::t) -> TypeRef {
3944

4045
fn type_of(cx: @crate_ctxt, t: ty::t) -> TypeRef {
4146
assert !ty::type_has_vars(t);
42-
// Check the cache.
4347

48+
#debug("type_of %?: %?", t, ty::get(t));
49+
50+
// Check the cache.
4451
if cx.lltypes.contains_key(t) { ret cx.lltypes.get(t); }
45-
let llty = alt ty::get(t).struct {
46-
ty::ty_nil | ty::ty_bot { T_nil() }
47-
ty::ty_bool { T_bool() }
48-
ty::ty_int(t) { T_int_ty(cx, t) }
49-
ty::ty_uint(t) { T_uint_ty(cx, t) }
50-
ty::ty_float(t) { T_float_ty(cx, t) }
51-
ty::ty_estr(ty::vstore_uniq) |
52-
ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
53-
ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
54-
ty::ty_estr(ty::vstore_box) { T_ptr(T_box(cx, T_i8())) }
55-
ty::ty_evec(mt, ty::vstore_box) |
56-
ty::ty_box(mt) { T_ptr(T_box(cx, type_of(cx, mt.ty))) }
57-
ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) }
58-
ty::ty_uniq(mt) { T_ptr(type_of(cx, mt.ty)) }
59-
ty::ty_evec(mt, ty::vstore_uniq) |
60-
ty::ty_vec(mt) { T_ptr(T_vec(cx, type_of(cx, mt.ty))) }
61-
ty::ty_ptr(mt) { T_ptr(type_of(cx, mt.ty)) }
62-
ty::ty_rptr(_, mt) { T_ptr(type_of(cx, mt.ty)) }
63-
64-
ty::ty_evec(mt, ty::vstore_slice(_)) {
65-
T_struct([T_ptr(type_of(cx, mt.ty)),
66-
T_uint_ty(cx, ast::ty_u)])
67-
}
6852

69-
ty::ty_estr(ty::vstore_slice(_)) {
70-
T_struct([T_ptr(T_i8()),
71-
T_uint_ty(cx, ast::ty_u)])
72-
}
53+
// Replace any typedef'd types with their equivalent non-typedef
54+
// type. This ensures that all LLVM nominal types that contain
55+
// Rust types are defined as the same LLVM types. If we don't do
56+
// this then, e.g. `option<{myfield: bool}>` would be a different
57+
// type than `option<myrec>`.
58+
let t_norm = ty::normalize_ty(cx.tcx, t);
59+
let llty = if t != t_norm {
60+
type_of(cx, t_norm)
61+
} else {
62+
alt ty::get(t).struct {
63+
ty::ty_nil | ty::ty_bot { T_nil() }
64+
ty::ty_bool { T_bool() }
65+
ty::ty_int(t) { T_int_ty(cx, t) }
66+
ty::ty_uint(t) { T_uint_ty(cx, t) }
67+
ty::ty_float(t) { T_float_ty(cx, t) }
68+
ty::ty_estr(ty::vstore_uniq) |
69+
ty::ty_str { T_ptr(T_vec(cx, T_i8())) }
70+
ty::ty_enum(did, _) { type_of_enum(cx, did, t) }
71+
ty::ty_estr(ty::vstore_box) { T_ptr(T_box(cx, T_i8())) }
72+
ty::ty_evec(mt, ty::vstore_box) |
73+
ty::ty_box(mt) { T_ptr(T_box(cx, type_of(cx, mt.ty))) }
74+
ty::ty_opaque_box { T_ptr(T_box(cx, T_i8())) }
75+
ty::ty_uniq(mt) { T_ptr(type_of(cx, mt.ty)) }
76+
ty::ty_evec(mt, ty::vstore_uniq) |
77+
ty::ty_vec(mt) { T_ptr(T_vec(cx, type_of(cx, mt.ty))) }
78+
ty::ty_ptr(mt) { T_ptr(type_of(cx, mt.ty)) }
79+
ty::ty_rptr(_, mt) { T_ptr(type_of(cx, mt.ty)) }
7380

74-
ty::ty_estr(ty::vstore_fixed(n)) {
75-
T_array(T_i8(), n + 1u /* +1 for trailing null */)
76-
}
81+
ty::ty_evec(mt, ty::vstore_slice(_)) {
82+
T_struct([T_ptr(type_of(cx, mt.ty)),
83+
T_uint_ty(cx, ast::ty_u)])
84+
}
7785

78-
ty::ty_evec(mt, ty::vstore_fixed(n)) {
79-
T_array(type_of(cx, mt.ty), n)
80-
}
86+
ty::ty_estr(ty::vstore_slice(_)) {
87+
T_struct([T_ptr(T_i8()),
88+
T_uint_ty(cx, ast::ty_u)])
89+
}
8190

82-
ty::ty_rec(fields) {
83-
let mut tys: [TypeRef] = [];
84-
for vec::each(fields) {|f|
85-
let mt_ty = f.mt.ty;
86-
tys += [type_of(cx, mt_ty)];
87-
}
88-
T_struct(tys)
89-
}
90-
ty::ty_fn(_) { T_fn_pair(cx, type_of_fn_from_ty(cx, t)) }
91-
ty::ty_iface(_, _) { T_opaque_iface(cx) }
92-
ty::ty_res(_, sub, substs) {
93-
let sub1 = ty::subst(cx.tcx, substs, sub);
94-
ret T_struct([T_i8(), type_of(cx, sub1)]);
95-
}
96-
ty::ty_param(_, _) { T_typaram(cx.tn) }
97-
ty::ty_type { T_ptr(cx.tydesc_type) }
98-
ty::ty_tup(elts) {
99-
let mut tys = [];
100-
for vec::each(elts) {|elt|
101-
tys += [type_of(cx, elt)];
91+
ty::ty_estr(ty::vstore_fixed(n)) {
92+
T_array(T_i8(), n + 1u /* +1 for trailing null */)
93+
}
94+
95+
ty::ty_evec(mt, ty::vstore_fixed(n)) {
96+
T_array(type_of(cx, mt.ty), n)
97+
}
98+
99+
ty::ty_rec(fields) {
100+
let mut tys: [TypeRef] = [];
101+
for vec::each(fields) {|f|
102+
let mt_ty = f.mt.ty;
103+
tys += [type_of(cx, mt_ty)];
104+
}
105+
T_struct(tys)
106+
}
107+
ty::ty_fn(_) { T_fn_pair(cx, type_of_fn_from_ty(cx, t)) }
108+
ty::ty_iface(_, _) { T_opaque_iface(cx) }
109+
ty::ty_res(_, sub, substs) {
110+
let sub1 = ty::subst(cx.tcx, substs, sub);
111+
ret T_struct([T_i8(), type_of(cx, sub1)]);
112+
}
113+
ty::ty_param(_, _) { T_typaram(cx.tn) }
114+
ty::ty_type { T_ptr(cx.tydesc_type) }
115+
ty::ty_tup(elts) {
116+
let mut tys = [];
117+
for vec::each(elts) {|elt|
118+
tys += [type_of(cx, elt)];
119+
}
120+
T_struct(tys)
121+
}
122+
ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
123+
ty::ty_constr(subt,_) { type_of(cx, subt) }
124+
ty::ty_class(did, ts) {
125+
// only instance vars are record fields at runtime
126+
let fields = lookup_class_fields(cx.tcx, did);
127+
let tys = vec::map(fields) {|f|
128+
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
129+
type_of(cx, t)
130+
};
131+
T_struct(tys)
132+
}
133+
ty::ty_self(_) { cx.tcx.sess.unimpl("type_of: ty_self \
134+
not implemented"); }
135+
ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
102136
}
103-
T_struct(tys)
104-
}
105-
ty::ty_opaque_closure_ptr(_) { T_opaque_box_ptr(cx) }
106-
ty::ty_constr(subt,_) { type_of(cx, subt) }
107-
ty::ty_class(did, ts) {
108-
// only instance vars are record fields at runtime
109-
let fields = lookup_class_fields(cx.tcx, did);
110-
let tys = vec::map(fields) {|f|
111-
let t = ty::lookup_field_type(cx.tcx, did, f.id, ts);
112-
type_of(cx, t)
113-
};
114-
T_struct(tys)
115-
}
116-
ty::ty_self(_) { cx.tcx.sess.unimpl("type_of: ty_self \
117-
not implemented"); }
118-
ty::ty_var(_) { cx.tcx.sess.bug("type_of shouldn't see a ty_var"); }
119137
};
120138
cx.lltypes.insert(t, llty);
121139
ret llty;
122140
}
123141

142+
// This should only be called from type_of, above, because it
143+
// creates new llvm named struct types lazily that are then
144+
// cached by type_of
124145
fn type_of_enum(cx: @crate_ctxt, did: ast::def_id, t: ty::t)
125146
-> TypeRef {
126-
let degen = (*ty::enum_variants(cx.tcx, did)).len() == 1u;
127-
let size = shape::static_size_of_enum(cx, t);
128-
if !degen { T_enum(cx, size) }
129-
else if size == 0u { T_struct([T_enum_variant(cx)]) }
130-
else { T_array(T_i8(), size) }
147+
148+
#debug("type_of_enum %?: %?", t, ty::get(t));
149+
150+
// Every enum type has a unique name. When we find our roots
151+
// for GC and unwinding we will use this name to rediscover
152+
// the Rust type
153+
let name = llvm_type_name(cx, t);
154+
155+
let named_llty = common::T_named_struct(name);
156+
157+
let lltys = {
158+
let degen = (*ty::enum_variants(cx.tcx, did)).len() == 1u;
159+
let size = shape::static_size_of_enum(cx, t);
160+
if !degen {
161+
[T_enum_variant(cx), T_array(T_i8(), size)]
162+
}
163+
else if size == 0u {
164+
[T_enum_variant(cx)]
165+
}
166+
else {
167+
[T_array(T_i8(), size)]
168+
}
169+
};
170+
171+
common::set_struct_body(named_llty, lltys);
172+
ret named_llty;
131173
}
174+
175+
fn llvm_type_name(cx: @crate_ctxt, t: ty::t) -> str {
176+
let (name, did, tps) = alt check ty::get(t).struct {
177+
ty::ty_enum(did, substs) {
178+
("enum", did, substs.tps)
179+
}
180+
};
181+
ret #fmt(
182+
"%s %s[#%d]",
183+
name,
184+
util::ppaux::parameterized(
185+
cx.tcx,
186+
ty::item_path_str(cx.tcx, did),
187+
none,
188+
tps),
189+
did.crate
190+
);
191+
}
192+

src/rustc/middle/ty.rs

+27
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ export ast_ty_to_ty_cache_entry;
149149
export atttce_unresolved, atttce_resolved;
150150
export mach_sty;
151151
export ty_sort_str;
152+
export normalize_ty;
152153

153154
// Data types
154155

@@ -2674,6 +2675,32 @@ fn ty_params_to_tys(tcx: ty::ctxt, tps: [ast::ty_param]) -> [t] {
26742675
ty::mk_param(tcx, i, ast_util::local_def(tps[i].id))
26752676
})
26762677
}
2678+
2679+
#[doc = "
2680+
Returns an equivalent type with all the typedefs and self regions removed.
2681+
"]
2682+
fn normalize_ty(cx: ctxt, t: t) -> t {
2683+
let t = alt get(t).struct {
2684+
ty_enum(did, r) {
2685+
alt r.self_r {
2686+
some(_) {
2687+
// This enum has a self region. Get rid of it
2688+
mk_enum(cx, did, {self_r: none, tps: r.tps })
2689+
}
2690+
none { t }
2691+
}
2692+
}
2693+
_ { t }
2694+
};
2695+
2696+
// FIXME #2187: This also reduced int types to their compatible machine
2697+
// types, which isn't necessary after #2187
2698+
let t = mk_t(cx, mach_sty(cx.sess.targ_cfg, t));
2699+
2700+
let sty = fold_sty(get(t).struct) {|t| normalize_ty(cx, t) };
2701+
mk_t(cx, sty)
2702+
}
2703+
26772704
// Local Variables:
26782705
// mode: rust
26792706
// fill-column: 78;

src/rustc/util/ppaux.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -128,25 +128,6 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
128128
fn field_to_str(cx: ctxt, f: field) -> str {
129129
ret f.ident + ": " + mt_to_str(cx, f.mt);
130130
}
131-
fn parameterized(cx: ctxt,
132-
base: str,
133-
self_r: option<ty::region>,
134-
tps: [ty::t]) -> str {
135-
136-
let r_str = alt self_r {
137-
none { "" }
138-
some(r) {
139-
#fmt["/%s", region_to_str(cx, r)]
140-
}
141-
};
142-
143-
if vec::len(tps) > 0u {
144-
let strs = vec::map(tps, {|t| ty_to_str(cx, t)});
145-
#fmt["%s%s<%s>", base, r_str, str::connect(strs, ",")]
146-
} else {
147-
#fmt["%s%s", base, r_str]
148-
}
149-
}
150131

151132
// if there is an id, print that instead of the structural type:
152133
alt ty::type_def_id(typ) {
@@ -233,6 +214,26 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
233214
}
234215
}
235216

217+
fn parameterized(cx: ctxt,
218+
base: str,
219+
self_r: option<ty::region>,
220+
tps: [ty::t]) -> str {
221+
222+
let r_str = alt self_r {
223+
none { "" }
224+
some(r) {
225+
#fmt["/%s", region_to_str(cx, r)]
226+
}
227+
};
228+
229+
if vec::len(tps) > 0u {
230+
let strs = vec::map(tps, {|t| ty_to_str(cx, t)});
231+
#fmt["%s%s<%s>", base, r_str, str::connect(strs, ",")]
232+
} else {
233+
#fmt["%s%s", base, r_str]
234+
}
235+
}
236+
236237
fn ty_to_short_str(cx: ctxt, typ: t) -> str {
237238
let mut s = encoder::encoded_ty(cx, typ);
238239
if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); }
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// The two functions returning `result` should by type compatibile
2+
// even though they use different int types. This will probably
3+
// not be true after #2187
4+
5+
#[no_core];
6+
7+
enum result<T, U> {
8+
ok(T),
9+
err(U)
10+
}
11+
12+
type error = int;
13+
14+
fn get_fd() -> result<int, error> {
15+
getsockopt_i64()
16+
}
17+
18+
fn getsockopt_i64() -> result<i64, error> {
19+
fail
20+
}
21+
22+
fn main() { }

0 commit comments

Comments
 (0)