Skip to content

Commit 1d7c9bd

Browse files
committed
trans: use sizing_type_of for interacting with potentially incomplete types.
1 parent d492d09 commit 1d7c9bd

File tree

3 files changed

+71
-59
lines changed

3 files changed

+71
-59
lines changed

src/librustc_trans/trans/abi.rs

+50-35
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ pub enum ArgKind {
6161
pub struct ArgType {
6262
pub kind: ArgKind,
6363
/// Original LLVM type
64+
pub original_ty: Type,
65+
/// Sizing LLVM type (pointers are opaque).
66+
/// Unlike original_ty, this is guaranteed to be complete.
67+
///
68+
/// For example, while we're computing the function pointer type in
69+
/// `struct Foo(fn(Foo));`, `original_ty` is still LLVM's `%Foo = {}`.
70+
/// The field type will likely end up being `void(%Foo)*`, but we cannot
71+
/// use `%Foo` to compute properties (e.g. size and alignment) of `Foo`,
72+
/// until `%Foo` is completed by having all of its field types inserted,
73+
/// so `ty` holds the "sizing type" of `Foo`, which replaces all pointers
74+
/// with opaque ones, resulting in `{i8*}` for `Foo`.
75+
/// ABI-specific logic can then look at the size, alignment and fields of
76+
/// `{i8*}` in order to determine how the argument will be passed.
77+
/// Only later will `original_ty` aka `%Foo` be used in the LLVM function
78+
/// pointer type, without ever having introspected it.
6479
pub ty: Type,
6580
/// Coerced LLVM Type
6681
pub cast: Option<Type>,
@@ -71,9 +86,10 @@ pub struct ArgType {
7186
}
7287

7388
impl ArgType {
74-
fn new(ty: Type) -> ArgType {
89+
fn new(original_ty: Type, ty: Type) -> ArgType {
7590
ArgType {
7691
kind: Direct,
92+
original_ty: original_ty,
7793
ty: ty,
7894
cast: None,
7995
pad: None,
@@ -90,14 +106,6 @@ impl ArgType {
90106
}
91107
}
92108

93-
fn c_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
94-
if ty.is_bool() {
95-
Type::i1(cx)
96-
} else {
97-
type_of::type_of(cx, ty)
98-
}
99-
}
100-
101109
/// Metadata describing how the arguments to a native function
102110
/// should be passed in order to respect the native ABI.
103111
///
@@ -147,13 +155,6 @@ impl FnType {
147155
Aapcs => llvm::CCallConv,
148156
};
149157

150-
let rty = match sig.output {
151-
ty::FnConverging(ret_ty) if !return_type_is_void(ccx, ret_ty) => {
152-
c_type_of(ccx, ret_ty)
153-
}
154-
_ => Type::void(ccx)
155-
};
156-
157158
let mut inputs = &sig.inputs[..];
158159
let extra_args = if abi == RustCall {
159160
assert!(!sig.variadic && extra_args.is_empty());
@@ -173,30 +174,45 @@ impl FnType {
173174
extra_args
174175
};
175176

177+
let arg_of = |ty: Ty<'tcx>| {
178+
if ty.is_bool() {
179+
let llty = Type::i1(ccx);
180+
let mut arg = ArgType::new(llty, llty);
181+
arg.attr = Some(llvm::Attribute::ZExt);
182+
arg
183+
} else {
184+
ArgType::new(type_of::type_of(ccx, ty),
185+
type_of::sizing_type_of(ccx, ty))
186+
}
187+
};
188+
189+
let ret = match sig.output {
190+
ty::FnConverging(ret_ty) if !return_type_is_void(ccx, ret_ty) => {
191+
arg_of(ret_ty)
192+
}
193+
_ => ArgType::new(Type::void(ccx), Type::void(ccx))
194+
};
195+
176196
let mut args = Vec::with_capacity(inputs.len() + extra_args.len());
177197
for ty in inputs.iter().chain(extra_args.iter()) {
178-
let llty = c_type_of(ccx, ty);
198+
let arg = arg_of(ty);
179199
if type_is_fat_ptr(ccx.tcx(), ty) {
180-
args.extend(llty.field_types().into_iter().map(ArgType::new));
200+
let original = arg.original_ty.field_types();
201+
let sizing = arg.ty.field_types();
202+
args.extend(original.into_iter().zip(sizing)
203+
.map(|(o, s)| ArgType::new(o, s)));
181204
} else {
182-
args.push(ArgType::new(llty));
205+
args.push(arg);
183206
}
184207
}
185208

186209
let mut fty = FnType {
187210
args: args,
188-
ret: ArgType::new(rty),
211+
ret: ret,
189212
variadic: sig.variadic,
190213
cconv: cconv
191214
};
192215

193-
// Add ZExt attributes to i1 arguments and returns.
194-
for arg in Some(&mut fty.ret).into_iter().chain(&mut fty.args) {
195-
if arg.ty == Type::i1(ccx) {
196-
arg.attr = Some(llvm::Attribute::ZExt);
197-
}
198-
}
199-
200216
if abi == Rust || abi == RustCall {
201217
let fixup = |arg: &mut ArgType| {
202218
if !arg.ty.is_aggregate() {
@@ -213,13 +229,12 @@ impl FnType {
213229
arg.cast = Some(Type::ix(ccx, size * 8));
214230
}
215231
};
216-
if let ty::FnConverging(ret_ty) = sig.output {
232+
if fty.ret.ty != Type::void(ccx) {
217233
// Fat pointers are returned by-value.
218-
if !type_is_fat_ptr(ccx.tcx(), ret_ty) &&
219-
fty.ret.ty != Type::void(ccx) {
234+
if !type_is_fat_ptr(ccx.tcx(), sig.output.unwrap()) {
220235
fixup(&mut fty.ret);
221236
}
222-
};
237+
}
223238
for arg in &mut fty.args {
224239
fixup(arg);
225240
}
@@ -256,10 +271,10 @@ impl FnType {
256271
let mut llargument_tys = Vec::new();
257272

258273
let llreturn_ty = if self.ret.is_indirect() {
259-
llargument_tys.push(self.ret.ty.ptr_to());
274+
llargument_tys.push(self.ret.original_ty.ptr_to());
260275
Type::void(ccx)
261276
} else {
262-
self.ret.cast.unwrap_or(self.ret.ty)
277+
self.ret.cast.unwrap_or(self.ret.original_ty)
263278
};
264279

265280
for arg in &self.args {
@@ -272,9 +287,9 @@ impl FnType {
272287
}
273288

274289
let llarg_ty = if arg.is_indirect() {
275-
arg.ty.ptr_to()
290+
arg.original_ty.ptr_to()
276291
} else {
277-
arg.cast.unwrap_or(arg.ty)
292+
arg.cast.unwrap_or(arg.original_ty)
278293
};
279294

280295
llargument_tys.push(llarg_ty);

src/librustc_trans/trans/foreign.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
203203
i,
204204
Value(llarg_rust),
205205
rust_indirect,
206-
arg_ty.ty);
206+
arg_ty);
207207

208208
// Ensure that we always have the Rust value indirectly,
209209
// because it makes bitcasting easier.
@@ -261,12 +261,9 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
261261
// type to match because some ABIs will use a different type than
262262
// the Rust type. e.g., a {u32,u32} struct could be returned as
263263
// u64.
264-
if fn_type.ret.ty != Type::void(ccx) && !fn_type.ret.is_indirect() {
265-
let llrust_ret_ty = fn_type.ret.ty;
266-
let llforeign_ret_ty = match fn_type.ret.cast {
267-
Some(ty) => ty,
268-
None => fn_type.ret.ty
269-
};
264+
let llrust_ret_ty = fn_type.ret.original_ty;
265+
if llrust_ret_ty != Type::void(ccx) && !fn_type.ret.is_indirect() {
266+
let llforeign_ret_ty = fn_type.ret.cast.unwrap_or(llrust_ret_ty);
270267

271268
debug!("llretptr={:?}", Value(llretptr));
272269
debug!("llforeign_retval={:?}", Value(llforeign_retval));
@@ -625,12 +622,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
625622
None, Some(attributes));
626623

627624
// Get the return value where the foreign fn expects it.
628-
let llforeign_ret_ty = match fn_ty.ret.cast {
629-
Some(ty) => ty,
630-
None => fn_ty.ret.ty
631-
};
625+
let llforeign_ret_ty = fn_ty.ret.cast.unwrap_or(fn_ty.ret.original_ty);
632626
match foreign_outptr {
633-
None if fn_ty.ret.ty == Type::void(ccx) => {
627+
None if llforeign_ret_ty == Type::void(ccx) => {
634628
// Function returns `()` or `bot`, which in Rust is the LLVM
635629
// type "{}" but in foreign ABIs is "Void".
636630
builder.ret_void();

src/librustc_trans/trans/type_of.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
108108

109109
let llsizingty = match t.sty {
110110
_ if !type_is_sized(cx.tcx(), t) => {
111-
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
111+
Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
112112
}
113113

114114
ty::TyBool => Type::bool(cx),
@@ -123,7 +123,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
123123
if type_is_sized(cx.tcx(), ty) {
124124
Type::i8p(cx)
125125
} else {
126-
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
126+
Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
127127
}
128128
}
129129

@@ -177,6 +177,18 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
177177
llsizingty
178178
}
179179

180+
fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
181+
let unsized_part = ccx.tcx().struct_tail(ty);
182+
match unsized_part.sty {
183+
ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
184+
Type::uint_from_ty(ccx, ast::UintTy::Us)
185+
}
186+
ty::TyTrait(_) => Type::vtable_ptr(ccx),
187+
_ => unreachable!("Unexpected tail in unsized_info_ty: {:?} for ty={:?}",
188+
unsized_part, ty)
189+
}
190+
}
191+
180192
pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
181193
if t.is_bool() {
182194
Type::i1(cx)
@@ -283,16 +295,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
283295
cx.tn().find_type("str_slice").unwrap()
284296
} else {
285297
let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
286-
let unsized_part = cx.tcx().struct_tail(ty);
287-
let info_ty = match unsized_part.sty {
288-
ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
289-
Type::uint_from_ty(cx, ast::UintTy::Us)
290-
}
291-
ty::TyTrait(_) => Type::vtable_ptr(cx),
292-
_ => panic!("Unexpected type returned from \
293-
struct_tail: {:?} for ty={:?}",
294-
unsized_part, ty)
295-
};
298+
let info_ty = unsized_info_ty(cx, ty);
296299
Type::struct_(cx, &[ptr_ty, info_ty], false)
297300
}
298301
} else {

0 commit comments

Comments
 (0)