diff options
author | John Hodge <tpg@mutabah.net> | 2017-01-01 15:35:45 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2017-01-01 15:35:45 +0800 |
commit | 57d08b51b8f0a9aa87953feaef43530ff861c91b (patch) | |
tree | e48d05860b6fae88a3d32484b5f718433645108e | |
parent | 4cd46a298c6611dd169eeae3ef7412f0c3af3289 (diff) | |
download | mrust-57d08b51b8f0a9aa87953feaef43530ff861c91b.tar.gz |
MIR/Trans - Fix DST field borrow hack
-rw-r--r-- | src/mir/cleanup.cpp | 40 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 30 |
2 files changed, 24 insertions, 46 deletions
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index f790c78a..3dc7f418 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -959,45 +959,7 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ) ) - if( se.src.is_Borrow() && se.src.as_Borrow().val.is_Field() ) - { - auto& e = se.src.as_Borrow(); - // TODO: If borrowing a !Sized value via a field access, create the DST - ::HIR::TypeRef tmp; - const auto& src_ty = state.get_lvalue_type(tmp, e.val); - - if( !resolve.type_is_sized(sp, src_ty) && !src_ty.m_data.is_Generic() ) - { - auto ty_unit_ptr = ::HIR::TypeRef::new_borrow( e.type, ::HIR::TypeRef::new_unit() ); - if( se.dst.is_Temporary() && state.get_lvalue_type(tmp, se.dst) == ty_unit_ptr ) - { - // Assigning fat pointer to a &() temporary, only happens if this has already happend - } - else - { - // Unwrap field accesses, next lvalue should be a deref - const ::MIR::LValue* lv = &e.val; - while( lv->is_Field() ) - lv = &*lv->as_Field().val; - MIR_ASSERT(state, lv->is_Deref(), "Access of !Sized field not via a deref"); - - const auto& dst_val_lval = *lv; - - auto meta_rval = ::MIR::RValue::make_DstMeta({ dst_val_lval.clone() }); - // TODO: How can the thin pointer to the field be obtained without tripping this twice? - auto ptr_rval = mv$( se.src ); - - // TODO: Get the metadata type. - auto meta_ty = ::HIR::TypeRef( ::HIR::CoreType::Usize ); - auto meta_lval = mutator.in_temporary( mv$(meta_ty), mv$(meta_rval) ); - - // HACK: Store the pointer as &() - auto ptr_lval = mutator.in_temporary( mv$(ty_unit_ptr), mv$(ptr_rval) ); - se.src = ::MIR::RValue::make_MakeDst({ mv$(ptr_lval), mv$(meta_lval) }); - } - } - } - + // Fix up RValue::Cast into coercions if( se.src.is_Cast() ) { auto& e = se.src.as_Cast(); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 82b78dd8..7bdce493 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -953,22 +953,38 @@ namespace { } ), (Borrow, - emit_lvalue(e.dst); - m_of << " = "; + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); bool special = false; // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata - TU_IFLET(::MIR::LValue, ve.val, Deref, e, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); // NOTE: Checks the result of the deref + TU_IFLET(::MIR::LValue, ve.val, Deref, le, if( metadata_type(ty) != MetadataType::None ) { - emit_lvalue(*e.val); + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(*le.val); special = true; } ) - // TODO: Magic for taking a &-ptr to unsized field of a struct. + // Magic for taking a &-ptr to unsized field of a struct. // - Needs to get metadata from bottom-level pointer. + else TU_IFLET(::MIR::LValue, ve.val, Field, le, + if( metadata_type(ty) != MetadataType::None ) { + const ::MIR::LValue* base_val = &*le.val; + while(base_val->is_Field()) + base_val = &*base_val->as_Field().val; + MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref"); + const ::MIR::LValue& base_ptr = *base_val->as_Deref().val; + + // Construct the new DST + emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; + emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val); + special = true; + } + ) if( !special ) { + emit_lvalue(e.dst); + m_of << " = "; m_of << "& "; emit_lvalue(ve.val); } ), |