Skip to content

Commit 654f14e

Browse files
author
Alexander Regueiro
committed
Implemented codegen.
1 parent 7c67713 commit 654f14e

File tree

3 files changed

+79
-63
lines changed

3 files changed

+79
-63
lines changed

src/librustc_codegen_ssa/base.rs

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -144,29 +144,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
144144
///
145145
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
146146
/// where the new vtable for an object will be derived from the old one.
147-
pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
148-
cx: &Cx,
147+
pub fn unsized_info<'tcx, 'a, Bx: BuilderMethods<'a, 'tcx>>(
148+
bx: &mut Bx,
149149
source: Ty<'tcx>,
150150
target: Ty<'tcx>,
151-
old_info: Option<Cx::Value>,
152-
) -> Cx::Value {
151+
old_info: Option<Bx::Value>,
152+
) -> Bx::Value {
153+
let tcx = bx.tcx();
153154
let (source, target) =
154-
cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env());
155+
tcx.struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
155156
match (&source.kind, &target.kind) {
156157
(&ty::Array(_, len), &ty::Slice(_)) => {
157-
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
158+
bx.cx().const_usize(len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
158159
}
159-
(&ty::Dynamic(..), &ty::Dynamic(..)) => {
160-
// For now, upcasts are limited to changes in marker
161-
// traits, and hence never actually require an actual
162-
// change to the vtable.
163-
old_info.expect("unsized_info: missing old info for trait upcast")
160+
(&ty::Dynamic(..), &ty::Dynamic(ref target_data, ..)) => {
161+
// Trait upcast
162+
163+
let source_ptr = old_info.expect("unsized_info: missing old info for trait upcast");
164+
let target_trait_ref = target_data.principal()
165+
.expect("target trait object of upcast does not have principal");
166+
167+
let trait_ref = target_trait_ref.with_self_ty(tcx, source);
168+
let vtable = tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref));
169+
let offset = match vtable {
170+
Vtable::VtableObject(ref data) => data.vtable_base,
171+
// HACK(alexreg): dubious solution to ICE in `manual-self-impl-for-unsafe-obj` test.
172+
Vtable::VtableImpl(_) => 0,
173+
_ => bug!("unsized_info: unexpected vtable kind {:?}", vtable),
174+
};
175+
176+
let vtable_layout = bx.cx().layout_of(tcx.mk_mut_ptr(source));
177+
let source_ptr = bx.pointercast(
178+
source_ptr,
179+
bx.cx().scalar_pair_element_backend_type(vtable_layout, 1, true),
180+
);
181+
182+
let target_ptr = bx.struct_gep(source_ptr, offset as u64);
183+
184+
let vtable_layout = bx.cx().layout_of(tcx.mk_mut_ptr(target));
185+
bx.pointercast(
186+
target_ptr,
187+
bx.cx().scalar_pair_element_backend_type(vtable_layout, 1, true),
188+
)
164189
}
165190
(_, &ty::Dynamic(ref data, ..)) => {
166-
let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target)).field(cx, FAT_PTR_EXTRA);
167-
cx.const_ptrcast(
168-
meth::get_vtable(cx, source, data.principal()),
169-
cx.backend_type(vtable_ptr),
191+
let vtable_layout = bx.cx().layout_of(tcx.mk_mut_ptr(target));
192+
bx.pointercast(
193+
meth::get_vtable(bx.cx(), source, data.principal()),
194+
bx.cx().scalar_pair_element_backend_type(vtable_layout, 1, true),
170195
)
171196
}
172197
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
@@ -186,7 +211,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
186211
| (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
187212
assert!(bx.cx().type_is_sized(a));
188213
let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
189-
(bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
214+
(bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, None))
190215
}
191216
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
192217
assert_eq!(def_a, def_b);
@@ -253,11 +278,35 @@ pub fn coerce_ptr_unsized<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
253278
}
254279
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
255280
assert_eq!(def_a, def_b);
256-
unsized_info(bx, src.ty, dst.ty, Some(info))
281+
282+
let mut result = None;
283+
for i in 0..src.fields.count() {
284+
let src_f = src.field(bx.cx(), i);
285+
assert_eq!(src.fields.offset(i).bytes(), 0);
286+
assert_eq!(dst.fields.offset(i).bytes(), 0);
287+
if src_f.is_zst() {
288+
continue;
289+
}
290+
assert_eq!(src.size, src_f.size);
291+
292+
let dst_f = dst.field(bx.cx(), i);
293+
assert_eq!(result, None);
294+
result = if src_f == dst_f {
295+
Some(info)
296+
} else {
297+
let f = op.extract_field(bx, i);
298+
return coerce_ptr_unsized(bx, f, dst_f);
299+
};
300+
}
301+
result.unwrap()
257302
}
258303
_ => bug!("coerce_ptr_unsized: called on bad types"),
259304
};
260-
(base, info)
305+
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
306+
// FIXME(eddyb) move these out of this `match` arm, so they're always
307+
// applied, uniformly, no matter the source/destination types.
308+
(bx.bitcast(base, bx.cx().scalar_pair_element_backend_type(dst, 0, true)),
309+
bx.bitcast(info, bx.cx().scalar_pair_element_backend_type(dst, 1, true)))
261310
}
262311
OperandValue::Immediate(base) => {
263312
unsize_thin_ptr(bx, base, src.ty, dst.ty)
@@ -283,23 +332,10 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
283332
let dst_ty = dst.layout.ty;
284333
match (&src_ty.kind, &dst_ty.kind) {
285334
(&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
286-
let (base, info) = match bx.load_operand(src).val {
287-
OperandValue::Pair(base, info) => {
288-
// fat-ptr to fat-ptr unsize preserves the vtable
289-
// i.e., &'a fmt::Debug+Send => &'a fmt::Debug
290-
// So we need to pointercast the base to ensure
291-
// the types match up.
292-
// FIXME(eddyb) use `scalar_pair_element_backend_type` here,
293-
// like `unsize_thin_ptr` does.
294-
let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR);
295-
(bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
296-
}
297-
OperandValue::Immediate(base) => unsize_thin_ptr(bx, base, src_ty, dst_ty),
298-
OperandValue::Ref(..) => bug!(),
299-
};
300-
OperandValue::Pair(base, info).store(bx, dst);
335+
let src_op = bx.load_operand(src);
336+
let dst_op = coerce_ptr_unsized(bx, src_op, dst.layout);
337+
dst_op.store(bx, dst);s
301338
}
302-
303339
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
304340
assert_eq!(def_a, def_b);
305341

src/librustc_codegen_ssa/mir/rvalue.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -224,35 +224,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
224224
operand.val
225225
}
226226
mir::CastKind::Pointer(PointerCast::Unsize) => {
227-
assert!(bx.cx().is_backend_scalar_pair(cast));
228-
match operand.val {
229-
OperandValue::Pair(lldata, llextra) => {
230-
// unsize from a fat pointer -- this is a
231-
// "trait-object-to-supertrait" coercion, for
232-
// example, `&'a fmt::Debug + Send => &'a fmt::Debug`.
233-
234-
// HACK(eddyb) have to bitcast pointers
235-
// until LLVM removes pointee types.
236-
let lldata = bx.pointercast(
237-
lldata,
238-
bx.cx().scalar_pair_element_backend_type(cast, 0, true),
239-
);
240-
OperandValue::Pair(lldata, llextra)
241-
}
242-
OperandValue::Immediate(lldata) => {
243-
// "standard" unsize
244-
let (lldata, llextra) = base::unsize_thin_ptr(
245-
&mut bx,
246-
lldata,
247-
operand.layout.ty,
248-
cast.ty,
249-
);
250-
OperandValue::Pair(lldata, llextra)
251-
}
252-
OperandValue::Ref(..) => {
253-
bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
254-
}
255-
}
227+
base::coerce_ptr_unsized(&mut bx, operand, cast)
256228
}
257229
mir::CastKind::Pointer(PointerCast::MutToConstPointer)
258230
| mir::CastKind::Misc

src/librustc_middle/ty/sty.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,14 @@ impl<'tcx> TyS<'tcx> {
18811881
}
18821882
}
18831883

1884+
/// Panics if called on any type other than `PhantomData<T>`.
1885+
pub fn phantom_ty(&self) -> Ty<'tcx> {
1886+
match self.kind {
1887+
Adt(def, substs) if def.is_phantom_data() => substs.type_at(0),
1888+
_ => bug!("`phantom_ty` is called on non-phantom-data type {:?}", self),
1889+
}
1890+
}
1891+
18841892
/// A scalar type is one that denotes an atomic datum, with no sub-components.
18851893
/// (A RawPtr is scalar because it represents a non-managed pointer, so its
18861894
/// contents are abstract to rustc.)

0 commit comments

Comments
 (0)