parent
31c908b7be
commit
59edfdd2ab
11 changed files with 313 additions and 85 deletions
|
@ -13,8 +13,10 @@ use middle::freevars::freevar_entry;
|
||||||
use middle::freevars;
|
use middle::freevars;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::{MethodCall, NoAdjustment};
|
use middle::ty_fold;
|
||||||
|
use middle::ty_fold::TypeFoldable;
|
||||||
use middle::typeck;
|
use middle::typeck;
|
||||||
|
use middle::typeck::{MethodCall, NoAdjustment};
|
||||||
use util::ppaux::{Repr, ty_to_string};
|
use util::ppaux::{Repr, ty_to_string};
|
||||||
use util::ppaux::UserString;
|
use util::ppaux::UserString;
|
||||||
|
|
||||||
|
@ -83,18 +85,29 @@ pub fn check_crate(tcx: &ty::ctxt,
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct EmptySubstsFolder<'a> {
|
||||||
|
tcx: &'a ty::ctxt
|
||||||
|
}
|
||||||
|
impl<'a> ty_fold::TypeFolder for EmptySubstsFolder<'a> {
|
||||||
|
fn tcx<'a>(&'a self) -> &'a ty::ctxt {
|
||||||
|
self.tcx
|
||||||
|
}
|
||||||
|
fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs {
|
||||||
|
subst::Substs::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_struct_safe_for_destructor(cx: &mut Context,
|
fn check_struct_safe_for_destructor(cx: &mut Context,
|
||||||
span: Span,
|
span: Span,
|
||||||
struct_did: DefId) {
|
struct_did: DefId) {
|
||||||
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
|
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
|
||||||
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
|
if !struct_tpt.generics.has_type_params(subst::TypeSpace)
|
||||||
&& !struct_tpt.generics.has_region_params(subst::TypeSpace) {
|
&& !struct_tpt.generics.has_region_params(subst::TypeSpace) {
|
||||||
let struct_ty = ty::mk_struct(cx.tcx, struct_did,
|
let mut folder = EmptySubstsFolder { tcx: cx.tcx };
|
||||||
subst::Substs::empty());
|
if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) {
|
||||||
if !ty::type_is_sendable(cx.tcx, struct_ty) {
|
|
||||||
span_err!(cx.tcx.sess, span, E0125,
|
span_err!(cx.tcx.sess, span, E0125,
|
||||||
"cannot implement a destructor on a \
|
"cannot implement a destructor on a \
|
||||||
structure that does not satisfy Send");
|
structure or enumeration that does not satisfy Send");
|
||||||
span_note!(cx.tcx.sess, span,
|
span_note!(cx.tcx.sess, span,
|
||||||
"use \"#[unsafe_destructor]\" on the implementation \
|
"use \"#[unsafe_destructor]\" on the implementation \
|
||||||
to force the compiler to allow this");
|
to force the compiler to allow this");
|
||||||
|
|
|
@ -53,7 +53,10 @@ use middle::subst;
|
||||||
use middle::subst::Subst;
|
use middle::subst::Subst;
|
||||||
use middle::trans::_match;
|
use middle::trans::_match;
|
||||||
use middle::trans::build::*;
|
use middle::trans::build::*;
|
||||||
|
use middle::trans::cleanup;
|
||||||
|
use middle::trans::cleanup::CleanupMethods;
|
||||||
use middle::trans::common::*;
|
use middle::trans::common::*;
|
||||||
|
use middle::trans::datum;
|
||||||
use middle::trans::machine;
|
use middle::trans::machine;
|
||||||
use middle::trans::type_::Type;
|
use middle::trans::type_::Type;
|
||||||
use middle::trans::type_of;
|
use middle::trans::type_of;
|
||||||
|
@ -83,8 +86,12 @@ pub enum Repr {
|
||||||
/**
|
/**
|
||||||
* General-case enums: for each case there is a struct, and they
|
* General-case enums: for each case there is a struct, and they
|
||||||
* all start with a field for the discriminant.
|
* all start with a field for the discriminant.
|
||||||
|
*
|
||||||
|
* Types with destructors need a dynamic destroyedness flag to
|
||||||
|
* avoid running the destructor too many times; the last argument
|
||||||
|
* indicates whether such a flag is present.
|
||||||
*/
|
*/
|
||||||
General(IntType, Vec<Struct>),
|
General(IntType, Vec<Struct>, bool),
|
||||||
/**
|
/**
|
||||||
* Two cases distinguished by a nullable pointer: the case with discriminant
|
* Two cases distinguished by a nullable pointer: the case with discriminant
|
||||||
* `nndiscr` must have single field which is known to be nonnull due to its type.
|
* `nndiscr` must have single field which is known to be nonnull due to its type.
|
||||||
|
@ -121,7 +128,7 @@ pub struct Struct {
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub align: u64,
|
pub align: u64,
|
||||||
pub packed: bool,
|
pub packed: bool,
|
||||||
pub fields: Vec<ty::t>,
|
pub fields: Vec<ty::t>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,14 +180,17 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||||
let cases = get_cases(cx.tcx(), def_id, substs);
|
let cases = get_cases(cx.tcx(), def_id, substs);
|
||||||
let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
|
let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
|
||||||
|
|
||||||
|
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
|
||||||
|
|
||||||
if cases.len() == 0 {
|
if cases.len() == 0 {
|
||||||
// Uninhabitable; represent as unit
|
// Uninhabitable; represent as unit
|
||||||
// (Typechecking will reject discriminant-sizing attrs.)
|
// (Typechecking will reject discriminant-sizing attrs.)
|
||||||
assert_eq!(hint, attr::ReprAny);
|
assert_eq!(hint, attr::ReprAny);
|
||||||
return Univariant(mk_struct(cx, [], false), false);
|
let ftys = if dtor { vec!(ty::mk_bool()) } else { vec!() };
|
||||||
|
return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cases.iter().all(|c| c.tys.len() == 0) {
|
if !dtor && cases.iter().all(|c| c.tys.len() == 0) {
|
||||||
// All bodies empty -> intlike
|
// All bodies empty -> intlike
|
||||||
let discrs: Vec<u64> = cases.iter().map(|c| c.discr).collect();
|
let discrs: Vec<u64> = cases.iter().map(|c| c.discr).collect();
|
||||||
let bounds = IntBounds {
|
let bounds = IntBounds {
|
||||||
|
@ -199,20 +209,19 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||||
cx.sess().bug(format!("non-C-like enum {} with specified \
|
cx.sess().bug(format!("non-C-like enum {} with specified \
|
||||||
discriminants",
|
discriminants",
|
||||||
ty::item_path_str(cx.tcx(),
|
ty::item_path_str(cx.tcx(),
|
||||||
def_id)).as_slice())
|
def_id)).as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
if cases.len() == 1 {
|
if cases.len() == 1 {
|
||||||
// Equivalent to a struct/tuple/newtype.
|
// Equivalent to a struct/tuple/newtype.
|
||||||
// (Typechecking will reject discriminant-sizing attrs.)
|
// (Typechecking will reject discriminant-sizing attrs.)
|
||||||
assert_eq!(hint, attr::ReprAny);
|
assert_eq!(hint, attr::ReprAny);
|
||||||
return Univariant(mk_struct(cx,
|
let mut ftys = cases.get(0).tys.clone();
|
||||||
cases.get(0).tys.as_slice(),
|
if dtor { ftys.push(ty::mk_bool()); }
|
||||||
false),
|
return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
|
||||||
false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cases.len() == 2 && hint == attr::ReprAny {
|
if !dtor && cases.len() == 2 && hint == attr::ReprAny {
|
||||||
// Nullable pointer optimization
|
// Nullable pointer optimization
|
||||||
let mut discr = 0;
|
let mut discr = 0;
|
||||||
while discr < 2 {
|
while discr < 2 {
|
||||||
|
@ -246,10 +255,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||||
let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
|
let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
|
||||||
slo: 0, shi: (cases.len() - 1) as i64 };
|
slo: 0, shi: (cases.len() - 1) as i64 };
|
||||||
let ity = range_to_inttype(cx, hint, &bounds);
|
let ity = range_to_inttype(cx, hint, &bounds);
|
||||||
|
|
||||||
return General(ity, cases.iter().map(|c| {
|
return General(ity, cases.iter().map(|c| {
|
||||||
let discr = vec!(ty_of_inttype(ity));
|
let mut ftys = vec!(ty_of_inttype(ity)).append(c.tys.as_slice());
|
||||||
mk_struct(cx, discr.append(c.tys.as_slice()).as_slice(), false)
|
if dtor { ftys.push(ty::mk_bool()); }
|
||||||
}).collect())
|
mk_struct(cx, ftys.as_slice(), false)
|
||||||
|
}).collect(), dtor);
|
||||||
}
|
}
|
||||||
_ => cx.sess().bug("adt::represent_type called on non-ADT type")
|
_ => cx.sess().bug("adt::represent_type called on non-ADT type")
|
||||||
}
|
}
|
||||||
|
@ -359,7 +370,6 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
|
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
|
||||||
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
|
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
|
||||||
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
|
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
|
||||||
|
@ -499,7 +509,7 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool
|
||||||
Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
|
Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
General(ity, ref sts) => {
|
General(ity, ref sts, _) => {
|
||||||
// We need a representation that has:
|
// We need a representation that has:
|
||||||
// * The alignment of the most-aligned field
|
// * The alignment of the most-aligned field
|
||||||
// * The size of the largest variant (rounded up to that alignment)
|
// * The size of the largest variant (rounded up to that alignment)
|
||||||
|
@ -584,7 +594,7 @@ pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Opti
|
||||||
val = load_discr(bcx, ity, scrutinee, min, max);
|
val = load_discr(bcx, ity, scrutinee, min, max);
|
||||||
signed = ity.is_signed();
|
signed = ity.is_signed();
|
||||||
}
|
}
|
||||||
General(ity, ref cases) => {
|
General(ity, ref cases, _) => {
|
||||||
let ptr = GEPi(bcx, scrutinee, [0, 0]);
|
let ptr = GEPi(bcx, scrutinee, [0, 0]);
|
||||||
val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
|
val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
|
||||||
signed = ity.is_signed();
|
signed = ity.is_signed();
|
||||||
|
@ -658,7 +668,7 @@ pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
|
||||||
_match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
_match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
||||||
discr as u64, true)))
|
discr as u64, true)))
|
||||||
}
|
}
|
||||||
General(ity, _) => {
|
General(ity, _, _) => {
|
||||||
_match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
_match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
|
||||||
discr as u64, true)))
|
discr as u64, true)))
|
||||||
}
|
}
|
||||||
|
@ -684,17 +694,21 @@ pub fn trans_set_discr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
|
||||||
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
|
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
|
||||||
val)
|
val)
|
||||||
}
|
}
|
||||||
General(ity, _) => {
|
General(ity, ref cases, dtor) => {
|
||||||
|
if dtor {
|
||||||
|
let ptr = trans_field_ptr(bcx, r, val, discr,
|
||||||
|
cases.get(discr as uint).fields.len() - 2);
|
||||||
|
Store(bcx, C_u8(bcx.ccx(), 1), ptr);
|
||||||
|
}
|
||||||
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
|
Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
|
||||||
GEPi(bcx, val, [0, 0]))
|
GEPi(bcx, val, [0, 0]))
|
||||||
}
|
}
|
||||||
Univariant(ref st, true) => {
|
Univariant(ref st, dtor) => {
|
||||||
assert_eq!(discr, 0);
|
assert_eq!(discr, 0);
|
||||||
|
if dtor {
|
||||||
Store(bcx, C_u8(bcx.ccx(), 1),
|
Store(bcx, C_u8(bcx.ccx(), 1),
|
||||||
GEPi(bcx, val, [0, st.fields.len() - 1]))
|
GEPi(bcx, val, [0, st.fields.len() - 1]));
|
||||||
}
|
}
|
||||||
Univariant(..) => {
|
|
||||||
assert_eq!(discr, 0);
|
|
||||||
}
|
}
|
||||||
RawNullablePointer { nndiscr, nnty, ..} => {
|
RawNullablePointer { nndiscr, nnty, ..} => {
|
||||||
if discr != nndiscr {
|
if discr != nndiscr {
|
||||||
|
@ -737,7 +751,9 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint {
|
||||||
assert_eq!(discr, 0);
|
assert_eq!(discr, 0);
|
||||||
st.fields.len() - (if dtor { 1 } else { 0 })
|
st.fields.len() - (if dtor { 1 } else { 0 })
|
||||||
}
|
}
|
||||||
General(_, ref cases) => cases.get(discr as uint).fields.len() - 1,
|
General(_, ref cases, dtor) => {
|
||||||
|
cases.get(discr as uint).fields.len() - 1 - (if dtor { 1 } else { 0 })
|
||||||
|
}
|
||||||
RawNullablePointer { nndiscr, ref nullfields, .. } => {
|
RawNullablePointer { nndiscr, ref nullfields, .. } => {
|
||||||
if discr == nndiscr { 1 } else { nullfields.len() }
|
if discr == nndiscr { 1 } else { nullfields.len() }
|
||||||
}
|
}
|
||||||
|
@ -762,7 +778,7 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
|
||||||
assert_eq!(discr, 0);
|
assert_eq!(discr, 0);
|
||||||
struct_field_ptr(bcx, st, val, ix, false)
|
struct_field_ptr(bcx, st, val, ix, false)
|
||||||
}
|
}
|
||||||
General(_, ref cases) => {
|
General(_, ref cases, _) => {
|
||||||
struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true)
|
struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true)
|
||||||
}
|
}
|
||||||
RawNullablePointer { nndiscr, ref nullfields, .. } |
|
RawNullablePointer { nndiscr, ref nullfields, .. } |
|
||||||
|
@ -788,11 +804,10 @@ pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
|
pub fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef,
|
||||||
needs_cast: bool) -> ValueRef {
|
ix: uint, needs_cast: bool) -> ValueRef {
|
||||||
let ccx = bcx.ccx();
|
|
||||||
|
|
||||||
let val = if needs_cast {
|
let val = if needs_cast {
|
||||||
|
let ccx = bcx.ccx();
|
||||||
let fields = st.fields.iter().map(|&ty| type_of::type_of(ccx, ty)).collect::<Vec<_>>();
|
let fields = st.fields.iter().map(|&ty| type_of::type_of(ccx, ty)).collect::<Vec<_>>();
|
||||||
let real_ty = Type::struct_(ccx, fields.as_slice(), st.packed);
|
let real_ty = Type::struct_(ccx, fields.as_slice(), st.packed);
|
||||||
PointerCast(bcx, val, real_ty.ptr_to())
|
PointerCast(bcx, val, real_ty.ptr_to())
|
||||||
|
@ -803,10 +818,71 @@ fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
|
||||||
GEPi(bcx, val, [0, ix])
|
GEPi(bcx, val, [0, ix])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the struct drop flag, if present.
|
pub fn fold_variants<'r, 'b>(
|
||||||
pub fn trans_drop_flag_ptr(bcx: &Block, r: &Repr, val: ValueRef) -> ValueRef {
|
bcx: &'b Block<'b>, r: &Repr, value: ValueRef,
|
||||||
|
f: |&'b Block<'b>, &Struct, ValueRef|: 'r -> &'b Block<'b>
|
||||||
|
) -> &'b Block<'b> {
|
||||||
|
let fcx = bcx.fcx;
|
||||||
match *r {
|
match *r {
|
||||||
Univariant(ref st, true) => GEPi(bcx, val, [0, st.fields.len() - 1]),
|
Univariant(ref st, _) => {
|
||||||
|
f(bcx, st, value)
|
||||||
|
}
|
||||||
|
General(ity, ref cases, _) => {
|
||||||
|
let ccx = bcx.ccx();
|
||||||
|
let unr_cx = fcx.new_temp_block("enum-variant-iter-unr");
|
||||||
|
Unreachable(unr_cx);
|
||||||
|
|
||||||
|
let discr_val = trans_get_discr(bcx, r, value, None);
|
||||||
|
let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len());
|
||||||
|
let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
|
||||||
|
|
||||||
|
for (discr, case) in cases.iter().enumerate() {
|
||||||
|
let mut variant_cx = fcx.new_temp_block(
|
||||||
|
format!("enum-variant-iter-{}", discr.to_string()).as_slice()
|
||||||
|
);
|
||||||
|
let rhs_val = C_integral(ll_inttype(ccx, ity), discr as u64, true);
|
||||||
|
AddCase(llswitch, rhs_val, variant_cx.llbb);
|
||||||
|
|
||||||
|
let fields = case.fields.iter().map(|&ty|
|
||||||
|
type_of::type_of(bcx.ccx(), ty)).collect::<Vec<_>>();
|
||||||
|
let real_ty = Type::struct_(ccx, fields.as_slice(), case.packed);
|
||||||
|
let variant_value = PointerCast(variant_cx, value, real_ty.ptr_to());
|
||||||
|
|
||||||
|
variant_cx = f(variant_cx, case, variant_value);
|
||||||
|
Br(variant_cx, bcx_next.llbb);
|
||||||
|
}
|
||||||
|
|
||||||
|
bcx_next
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the struct drop flag, if present.
|
||||||
|
pub fn trans_drop_flag_ptr<'b>(mut bcx: &'b Block<'b>, r: &Repr,
|
||||||
|
val: ValueRef) -> datum::DatumBlock<'b, datum::Expr> {
|
||||||
|
let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), ty::mk_bool());
|
||||||
|
match *r {
|
||||||
|
Univariant(ref st, true) => {
|
||||||
|
let flag_ptr = GEPi(bcx, val, [0, st.fields.len() - 1]);
|
||||||
|
datum::immediate_rvalue_bcx(bcx, flag_ptr, ptr_ty).to_expr_datumblock()
|
||||||
|
}
|
||||||
|
General(_, _, true) => {
|
||||||
|
let fcx = bcx.fcx;
|
||||||
|
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
|
||||||
|
let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
|
||||||
|
bcx, ty::mk_bool(), "drop_flag", false,
|
||||||
|
cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
|
||||||
|
));
|
||||||
|
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
|
||||||
|
let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
|
||||||
|
datum::Datum::new(ptr, ptr_ty, datum::Rvalue::new(datum::ByRef))
|
||||||
|
.store_to(variant_cx, scratch.val)
|
||||||
|
});
|
||||||
|
let expr_datum = scratch.to_expr_datum();
|
||||||
|
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
|
||||||
|
datum::DatumBlock::new(bcx, expr_datum)
|
||||||
|
}
|
||||||
_ => bcx.ccx().sess().bug("tried to get drop flag of non-droppable type")
|
_ => bcx.ccx().sess().bug("tried to get drop flag of non-droppable type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,7 +916,7 @@ pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
|
||||||
assert_discr_in_range(ity, min, max, discr);
|
assert_discr_in_range(ity, min, max, discr);
|
||||||
C_integral(ll_inttype(ccx, ity), discr as u64, true)
|
C_integral(ll_inttype(ccx, ity), discr as u64, true)
|
||||||
}
|
}
|
||||||
General(ity, ref cases) => {
|
General(ity, ref cases, _) => {
|
||||||
let case = cases.get(discr as uint);
|
let case = cases.get(discr as uint);
|
||||||
let max_sz = cases.iter().map(|x| x.size).max().unwrap();
|
let max_sz = cases.iter().map(|x| x.size).max().unwrap();
|
||||||
let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
|
let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
|
||||||
|
@ -964,7 +1040,7 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
|
||||||
attr::UnsignedInt(..) => const_to_uint(val) as Disr
|
attr::UnsignedInt(..) => const_to_uint(val) as Disr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
General(ity, _) => {
|
General(ity, _, _) => {
|
||||||
match ity {
|
match ity {
|
||||||
attr::SignedInt(..) => const_to_int(const_get_elt(ccx, val, [0])) as Disr,
|
attr::SignedInt(..) => const_to_int(const_get_elt(ccx, val, [0])) as Disr,
|
||||||
attr::UnsignedInt(..) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr
|
attr::UnsignedInt(..) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr
|
||||||
|
|
|
@ -1856,7 +1856,7 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span,
|
||||||
|
|
||||||
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
|
let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
|
||||||
match *avar {
|
match *avar {
|
||||||
adt::General(_, ref variants) => {
|
adt::General(_, ref variants, _) => {
|
||||||
for var in variants.iter() {
|
for var in variants.iter() {
|
||||||
let mut size = 0;
|
let mut size = 0;
|
||||||
for field in var.fields.iter().skip(1) {
|
for field in var.fields.iter().skip(1) {
|
||||||
|
|
|
@ -1993,7 +1993,7 @@ struct EnumMemberDescriptionFactory {
|
||||||
impl EnumMemberDescriptionFactory {
|
impl EnumMemberDescriptionFactory {
|
||||||
fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription> {
|
fn create_member_descriptions(&self, cx: &CrateContext) -> Vec<MemberDescription> {
|
||||||
match *self.type_rep {
|
match *self.type_rep {
|
||||||
adt::General(_, ref struct_defs) => {
|
adt::General(_, ref struct_defs, _) => {
|
||||||
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
|
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
|
||||||
.expect(""));
|
.expect(""));
|
||||||
|
|
||||||
|
@ -2362,7 +2362,7 @@ fn prepare_enum_metadata(cx: &CrateContext,
|
||||||
adt::RawNullablePointer { .. } |
|
adt::RawNullablePointer { .. } |
|
||||||
adt::StructWrappedNullablePointer { .. } |
|
adt::StructWrappedNullablePointer { .. } |
|
||||||
adt::Univariant(..) => None,
|
adt::Univariant(..) => None,
|
||||||
adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
|
adt::General(inttype, _, _) => Some(discriminant_type_metadata(inttype)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let enum_llvm_type = type_of::type_of(cx, enum_type);
|
let enum_llvm_type = type_of::type_of(cx, enum_type);
|
||||||
|
|
|
@ -204,7 +204,7 @@ fn make_visit_glue<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
|
fn trans_struct_drop_flag<'a>(mut bcx: &'a Block<'a>,
|
||||||
t: ty::t,
|
t: ty::t,
|
||||||
v0: ValueRef,
|
v0: ValueRef,
|
||||||
dtor_did: ast::DefId,
|
dtor_did: ast::DefId,
|
||||||
|
@ -212,8 +212,8 @@ fn trans_struct_drop_flag<'a>(bcx: &'a Block<'a>,
|
||||||
substs: &subst::Substs)
|
substs: &subst::Substs)
|
||||||
-> &'a Block<'a> {
|
-> &'a Block<'a> {
|
||||||
let repr = adt::represent_type(bcx.ccx(), t);
|
let repr = adt::represent_type(bcx.ccx(), t);
|
||||||
let drop_flag = adt::trans_drop_flag_ptr(bcx, &*repr, v0);
|
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, v0));
|
||||||
with_cond(bcx, load_ty(bcx, drop_flag, ty::mk_bool()), |cx| {
|
with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
|
||||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -237,33 +237,33 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||||
ty.element_type().func_params()
|
ty.element_type().func_params()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class dtors have no explicit args, so the params should
|
adt::fold_variants(bcx, &*repr, v0, |variant_cx, st, value| {
|
||||||
// just consist of the environment (self)
|
|
||||||
assert_eq!(params.len(), 1);
|
|
||||||
|
|
||||||
// Be sure to put all of the fields into a scope so we can use an invoke
|
// Be sure to put all of the fields into a scope so we can use an invoke
|
||||||
// instruction to call the user destructor but still call the field
|
// instruction to call the user destructor but still call the field
|
||||||
// destructors if the user destructor fails.
|
// destructors if the user destructor fails.
|
||||||
let field_scope = bcx.fcx.push_custom_cleanup_scope();
|
let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
|
||||||
|
|
||||||
let self_arg = PointerCast(bcx, v0, *params.get(0));
|
// Class dtors have no explicit args, so the params should
|
||||||
|
// just consist of the environment (self).
|
||||||
|
assert_eq!(params.len(), 1);
|
||||||
|
let self_arg = PointerCast(variant_cx, value, *params.get(0));
|
||||||
let args = vec!(self_arg);
|
let args = vec!(self_arg);
|
||||||
|
|
||||||
// Add all the fields as a value which needs to be cleaned at the end of
|
// Add all the fields as a value which needs to be cleaned at the end of
|
||||||
// this scope.
|
// this scope.
|
||||||
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
|
for (i, ty) in st.fields.iter().enumerate() {
|
||||||
for (i, fld) in field_tys.iter().enumerate() {
|
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
|
||||||
let llfld_a = adt::trans_field_ptr(bcx, &*repr, v0, 0, i);
|
variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
|
||||||
bcx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
|
llfld_a, *ty);
|
||||||
llfld_a,
|
|
||||||
fld.mt.ty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), ast::DUMMY_NODE_ID,
|
let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID,
|
||||||
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
|
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
|
||||||
let (_, bcx) = invoke(bcx, dtor_addr, args, dtor_ty, None);
|
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None);
|
||||||
|
|
||||||
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
|
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
|
||||||
|
variant_cx
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
|
fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
|
||||||
|
@ -317,7 +317,7 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::ty_struct(did, ref substs) => {
|
ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) => {
|
||||||
let tcx = bcx.tcx();
|
let tcx = bcx.tcx();
|
||||||
match ty::ty_dtor(tcx, did) {
|
match ty::ty_dtor(tcx, did) {
|
||||||
ty::TraitDtor(dtor, true) => {
|
ty::TraitDtor(dtor, true) => {
|
||||||
|
|
|
@ -2106,13 +2106,16 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||||
|
|
||||||
ty_enum(did, ref substs) => {
|
ty_enum(did, ref substs) => {
|
||||||
let variants = substd_enum_variants(cx, did, substs);
|
let variants = substd_enum_variants(cx, did, substs);
|
||||||
let res =
|
let mut res =
|
||||||
TypeContents::union(variants.as_slice(), |variant| {
|
TypeContents::union(variants.as_slice(), |variant| {
|
||||||
TypeContents::union(variant.args.as_slice(),
|
TypeContents::union(variant.args.as_slice(),
|
||||||
|arg_ty| {
|
|arg_ty| {
|
||||||
tc_ty(cx, *arg_ty, cache)
|
tc_ty(cx, *arg_ty, cache)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
if ty::has_dtor(cx, did) {
|
||||||
|
res = res | TC::OwnsDtor;
|
||||||
|
}
|
||||||
apply_lang_items(cx, did, res)
|
apply_lang_items(cx, did, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3778,17 +3781,13 @@ pub enum DtorKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DtorKind {
|
impl DtorKind {
|
||||||
pub fn is_not_present(&self) -> bool {
|
pub fn is_present(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
NoDtor => true,
|
TraitDtor(..) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_present(&self) -> bool {
|
|
||||||
!self.is_not_present()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_drop_flag(&self) -> bool {
|
pub fn has_drop_flag(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
&NoDtor => false,
|
&NoDtor => false,
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Foo {
|
impl Drop for Foo {
|
||||||
//~^ ERROR cannot implement a destructor on a structure that does not satisfy Send
|
//~^ ERROR cannot implement a destructor on a structure or enumeration that does not satisfy Send
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
94
src/test/run-pass/drop-trait-enum.rs
Normal file
94
src/test/run-pass/drop-trait-enum.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
#![feature(struct_variant)]
|
||||||
|
|
||||||
|
use std::task;
|
||||||
|
|
||||||
|
#[deriving(PartialEq, Show)]
|
||||||
|
enum Message {
|
||||||
|
Dropped,
|
||||||
|
DestructorRan
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SendOnDrop {
|
||||||
|
sender: Sender<Message>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SendOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.sender.send(Dropped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Foo {
|
||||||
|
SimpleVariant(Sender<Message>),
|
||||||
|
NestedVariant(Box<uint>, SendOnDrop, Sender<Message>),
|
||||||
|
FailingVariant { on_drop: SendOnDrop }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match self {
|
||||||
|
&SimpleVariant(ref mut sender) => {
|
||||||
|
sender.send(DestructorRan);
|
||||||
|
}
|
||||||
|
&NestedVariant(_, _, ref mut sender) => {
|
||||||
|
sender.send(DestructorRan);
|
||||||
|
}
|
||||||
|
&FailingVariant { .. } => {
|
||||||
|
fail!("Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
{
|
||||||
|
let v = SimpleVariant(sender);
|
||||||
|
}
|
||||||
|
assert_eq!(receiver.recv(), DestructorRan);
|
||||||
|
assert_eq!(receiver.recv_opt().ok(), None);
|
||||||
|
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
{
|
||||||
|
let v = NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender);
|
||||||
|
}
|
||||||
|
assert_eq!(receiver.recv(), DestructorRan);
|
||||||
|
assert_eq!(receiver.recv(), Dropped);
|
||||||
|
assert_eq!(receiver.recv_opt().ok(), None);
|
||||||
|
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
task::spawn(proc() {
|
||||||
|
let v = FailingVariant { on_drop: SendOnDrop { sender: sender } };
|
||||||
|
});
|
||||||
|
assert_eq!(receiver.recv(), Dropped);
|
||||||
|
assert_eq!(receiver.recv_opt().ok(), None);
|
||||||
|
|
||||||
|
let (sender, receiver) = channel();
|
||||||
|
{
|
||||||
|
task::spawn(proc() {
|
||||||
|
let mut v = NestedVariant(box 42u, SendOnDrop {
|
||||||
|
sender: sender.clone()
|
||||||
|
}, sender.clone());
|
||||||
|
v = NestedVariant(box 42u, SendOnDrop { sender: sender.clone() }, sender.clone());
|
||||||
|
v = SimpleVariant(sender.clone());
|
||||||
|
v = FailingVariant { on_drop: SendOnDrop { sender: sender } };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
assert_eq!(receiver.recv(), DestructorRan);
|
||||||
|
assert_eq!(receiver.recv(), Dropped);
|
||||||
|
assert_eq!(receiver.recv(), DestructorRan);
|
||||||
|
assert_eq!(receiver.recv(), Dropped);
|
||||||
|
assert_eq!(receiver.recv(), DestructorRan);
|
||||||
|
assert_eq!(receiver.recv(), Dropped);
|
||||||
|
assert_eq!(receiver.recv_opt().ok(), None);
|
||||||
|
}
|
19
src/test/run-pass/drop-uninhabited-enum.rs
Normal file
19
src/test/run-pass/drop-uninhabited-enum.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
enum Foo { }
|
||||||
|
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(&mut self) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(x: Foo) { }
|
||||||
|
|
||||||
|
fn main() { }
|
|
@ -8,8 +8,10 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
struct DroppableStruct;
|
struct DroppableStruct;
|
||||||
|
enum DroppableEnum {
|
||||||
|
DroppableVariant1, DroppableVariant2
|
||||||
|
}
|
||||||
|
|
||||||
static mut DROPPED: bool = false;
|
static mut DROPPED: bool = false;
|
||||||
|
|
||||||
|
@ -18,9 +20,15 @@ impl Drop for DroppableStruct {
|
||||||
unsafe { DROPPED = true; }
|
unsafe { DROPPED = true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for DroppableEnum {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { DROPPED = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait MyTrait { }
|
trait MyTrait { }
|
||||||
impl MyTrait for Box<DroppableStruct> {}
|
impl MyTrait for Box<DroppableStruct> {}
|
||||||
|
impl MyTrait for Box<DroppableEnum> {}
|
||||||
|
|
||||||
struct Whatever { w: Box<MyTrait> }
|
struct Whatever { w: Box<MyTrait> }
|
||||||
impl Whatever {
|
impl Whatever {
|
||||||
|
@ -35,4 +43,10 @@ fn main() {
|
||||||
let _a = Whatever::new(box f as Box<MyTrait>);
|
let _a = Whatever::new(box f as Box<MyTrait>);
|
||||||
}
|
}
|
||||||
assert!(unsafe { DROPPED });
|
assert!(unsafe { DROPPED });
|
||||||
|
unsafe { DROPPED = false; }
|
||||||
|
{
|
||||||
|
let f = box DroppableVariant1;
|
||||||
|
let _a = Whatever::new(box f as Box<MyTrait>);
|
||||||
|
}
|
||||||
|
assert!(unsafe { DROPPED });
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
struct Foo;
|
struct Foo;
|
||||||
struct Bar { x: int }
|
struct Bar { x: int }
|
||||||
struct Baz(int);
|
struct Baz(int);
|
||||||
|
enum FooBar { _Foo(Foo), _Bar(uint) }
|
||||||
|
|
||||||
static mut NUM_DROPS: uint = 0;
|
static mut NUM_DROPS: uint = 0;
|
||||||
|
|
||||||
|
@ -32,6 +33,11 @@ impl Drop for Baz {
|
||||||
unsafe { NUM_DROPS += 1; }
|
unsafe { NUM_DROPS += 1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for FooBar {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { NUM_DROPS += 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 0);
|
assert_eq!(unsafe { NUM_DROPS }, 0);
|
||||||
|
@ -41,12 +47,19 @@ fn main() {
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 2);
|
assert_eq!(unsafe { NUM_DROPS }, 2);
|
||||||
{ let _x = Baz(21); }
|
{ let _x = Baz(21); }
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 3);
|
assert_eq!(unsafe { NUM_DROPS }, 3);
|
||||||
|
{ let _x = _Foo(Foo); }
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 3);
|
|
||||||
{ let _ = Foo; }
|
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 4);
|
|
||||||
{ let _ = Bar { x: 21 }; }
|
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 5);
|
assert_eq!(unsafe { NUM_DROPS }, 5);
|
||||||
{ let _ = Baz(21); }
|
{ let _x = _Bar(42u); }
|
||||||
assert_eq!(unsafe { NUM_DROPS }, 6);
|
assert_eq!(unsafe { NUM_DROPS }, 6);
|
||||||
|
|
||||||
|
{ let _ = Foo; }
|
||||||
|
assert_eq!(unsafe { NUM_DROPS }, 7);
|
||||||
|
{ let _ = Bar { x: 21 }; }
|
||||||
|
assert_eq!(unsafe { NUM_DROPS }, 8);
|
||||||
|
{ let _ = Baz(21); }
|
||||||
|
assert_eq!(unsafe { NUM_DROPS }, 9);
|
||||||
|
{ let _ = _Foo(Foo); }
|
||||||
|
assert_eq!(unsafe { NUM_DROPS }, 11);
|
||||||
|
{ let _ = _Bar(42u); }
|
||||||
|
assert_eq!(unsafe { NUM_DROPS }, 12);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue