summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir_expand/vtable.cpp12
-rw-r--r--src/trans/codegen_c.cpp309
2 files changed, 225 insertions, 96 deletions
diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp
index 45e531b8..81c0de00 100644
--- a/src/hir_expand/vtable.cpp
+++ b/src/hir_expand/vtable.cpp
@@ -186,6 +186,18 @@ namespace {
};
VtableConstruct vtc { this, &tr, {} };
+ // - Drop glue pointer
+ ::HIR::FunctionType ft;
+ ft.is_unsafe = false;
+ ft.m_abi = ABI_RUST;
+ ft.m_rettype.reset( new ::HIR::TypeRef(::HIR::TypeRef::new_unit()) );
+ ft.m_arg_types.push_back( ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ::HIR::TypeRef::new_unit()) );
+ vtc.fields.push_back(::std::make_pair( "#drop_glue", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::TypeRef(mv$(ft)) } ));
+ // - Size of data
+ vtc.fields.push_back(::std::make_pair( "#size", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ // - Alignment of data
+ vtc.fields.push_back(::std::make_pair( "#align", ::HIR::VisEnt<::HIR::TypeRef> { false, ::HIR::CoreType::Usize } ));
+ // - Add methods
if( ! vtc.add_ents_from_trait(tr, trait_path) )
{
tr.m_value_indexes.clear();
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index b8770c30..3d1134f2 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -252,7 +252,7 @@ namespace {
<< "typedef uint32_t RUST_CHAR;\n"
<< "typedef struct { void* PTR; size_t META; } SLICE_PTR;\n"
<< "typedef struct { void* PTR; void* META; } TRAITOBJ_PTR;\n"
- << "typedef struct { size_t size; size_t align; void (*drop)(void*); } VTABLE_HDR;\n"
+ << "typedef struct { void (*drop)(void*); size_t size; size_t align; } VTABLE_HDR;\n"
;
if( m_options.disallow_empty_structs )
{
@@ -441,7 +441,7 @@ namespace {
<< "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n"
<< "\n"
<< "static inline size_t mrustc_max(size_t a, size_t b) { return a < b ? b : a; }\n"
- << "static inline void noop_drop(void *p) {}\n"
+ << "static inline tUNIT noop_drop(tUNIT *p) {}\n"
<< "\n"
// A linear (fast-fail) search of a list of strings
<< "static inline size_t mrustc_string_search_linear(SLICE_PTR val, size_t count, SLICE_PTR* options) {\n"
@@ -806,13 +806,16 @@ namespace {
auto ty_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ty.clone());
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), ty_ptr, args, empty_fcn };
m_mir_res = &mir_res;
- m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {";
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
- for(const auto& ity : te)
+ m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {\n";
+ if( m_resolve.type_needs_drop_glue(sp, ty) )
{
- emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
- fld_lv.as_Field().field_index ++;
+ auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ for(const auto& ity : te)
+ {
+ emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
+ fld_lv.as_Field().field_index ++;
+ }
}
m_of << "}\n";
)
@@ -863,13 +866,6 @@ namespace {
}
m_of << "struct s_" << Trans_Mangle(p) << " {\n";
- // HACK: For vtables, insert the alignment and size at the start
- // TODO: This should be done in HIR, not here
- if(is_vtable)
- {
- m_of << "\tVTABLE_HDR hdr;\n";
- }
-
::std::vector<unsigned> fields;
for(const auto& ent : repr->fields)
{
@@ -899,7 +895,7 @@ namespace {
size_t s, a;
Target_GetSizeAndAlignOf(sp, m_resolve, ty, s, a);
if( s == 0 && m_options.disallow_empty_structs ) {
- m_of << "// ZST\n";
+ m_of << "// ZST: " << ty << "\n";
continue ;
}
else {
@@ -962,19 +958,21 @@ namespace {
::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, empty_fcn };
m_mir_res = &mir_res;
m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ") {\n";
-
- // If this type has an impl of Drop, call that impl
- if( item.m_markings.has_drop_impl ) {
- m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n";
- }
-
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
- for(size_t i = 0; i < repr->fields.size(); i++)
+ if( m_resolve.type_needs_drop_glue(sp, item_ty) )
{
- fld_lv.as_Field().field_index = i;
+ // If this type has an impl of Drop, call that impl
+ if( item.m_markings.has_drop_impl ) {
+ m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n";
+ }
+
+ auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ for(size_t i = 0; i < repr->fields.size(); i++)
+ {
+ fld_lv.as_Field().field_index = i;
- emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1);
+ emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1);
+ }
}
m_of << "}\n";
m_mir_res = nullptr;
@@ -1159,40 +1157,42 @@ namespace {
}
m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n";
-
- // If this type has an impl of Drop, call that impl
- if( item.m_markings.has_drop_impl )
- {
- m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
- }
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
-
- if( const auto* e = repr->variants.opt_NonZero() )
- {
- unsigned idx = 1 - e->zero_variant;
- // TODO: Fat pointers?
- m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 );
- m_of << "\t}\n";
- }
- else if( repr->fields.size() <= 1 )
+ if( m_resolve.type_needs_drop_glue(sp, item_ty) )
{
- // Value enum
- // Glue does nothing (except call the destructor, if there is one)
- }
- else if( const auto* e = repr->variants.opt_Values() )
- {
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ // If this type has an impl of Drop, call that impl
+ if( item.m_markings.has_drop_impl )
+ {
+ m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
+ }
+ auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- m_of << "\tswitch(rv->TAG) {\n";
- for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
+ if( const auto* e = repr->variants.opt_NonZero() )
+ {
+ unsigned idx = 1 - e->zero_variant;
+ // TODO: Fat pointers?
+ m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n";
+ emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 );
+ m_of << "\t}\n";
+ }
+ else if( repr->fields.size() <= 1 )
{
- var_lv.as_Downcast().variant_index = var_idx;
- m_of << "\tcase " << e->values[var_idx] << ":\n";
- emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2);
- m_of << "\tbreak;\n";
+ // Value enum
+ // Glue does nothing (except call the destructor, if there is one)
+ }
+ else if( const auto* e = repr->variants.opt_Values() )
+ {
+ auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+
+ m_of << "\tswitch(rv->TAG) {\n";
+ for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
+ {
+ var_lv.as_Downcast().variant_index = var_idx;
+ m_of << "\tcase " << e->values[var_idx] << ":\n";
+ emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2);
+ m_of << "\tbreak;\n";
+ }
+ m_of << "\t}\n";
}
- m_of << "\t}\n";
}
m_of << "}\n";
m_mir_res = nullptr;
@@ -1299,13 +1299,22 @@ namespace {
}
m_of << ") {\n";
m_of << "\tstruct s_" << Trans_Mangle(p) << " rv = {";
+ bool emitted = false;
for(unsigned int i = 0; i < e.size(); i ++)
{
- if(i != 0)
+ if( this->type_is_bad_zst(monomorph(e[i].ent)) )
+ continue ;
+ if(emitted)
m_of << ",";
+ emitted = true;
m_of << "\n\t\t_" << i;
}
- m_of << "\n\t\t};\n";
+ if( !emitted )
+ {
+ m_of << "\n\t\t0";
+ }
+ m_of << "\n";
+ m_of << "\t\t};\n";
m_of << "\treturn rv;\n";
m_of << "}\n";
}
@@ -1753,25 +1762,23 @@ namespace {
auto monomorph_cb_trait = monomorphise_type_get_cb(sp, &type, &trait_path.m_params, nullptr);
// Size, Alignment, and destructor
- m_of << "\t{ ";
- m_of << "sizeof("; emit_ctype(type); m_of << "),";
- m_of << "ALIGNOF("; emit_ctype(type); m_of << "),";
if( type.m_data.is_Borrow() || m_resolve.type_is_copy(sp, type) )
{
- m_of << "noop_drop,";
+ m_of << "\t""noop_drop,\n";
}
else
{
- m_of << "(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ",";
+ m_of << "\t""(void*)" << Trans_Mangle(::HIR::Path(type.clone(), "#drop_glue")) << ",\n";
}
- m_of << "}"; // No newline, added below
+ m_of << "\t""sizeof("; emit_ctype(type); m_of << "),\n";
+ m_of << "\t""ALIGNOF("; emit_ctype(type); m_of << "),\n";
for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ )
{
- m_of << ",\n";
+ // Find the corresponding vtable entry
for(const auto& m : trait.m_value_indexes)
{
- if( m.second.first != i )
+ if( m.second.first != 3+i )
continue ;
//MIR_ASSERT(*m_mir_res, tr.m_values.at(m.first).is_Function(), "TODO: Handle generating vtables with non-function items");
@@ -1779,10 +1786,9 @@ namespace {
auto gpath = monomorphise_genericpath_with(sp, m.second.second, monomorph_cb_trait, false);
// NOTE: `void*` cast avoids mismatched pointer type errors due to the receiver being &mut()/&() in the vtable
- m_of << "\t(void*)" << Trans_Mangle( ::HIR::Path(type.clone(), mv$(gpath), m.first) );
+ m_of << "\t(void*)" << Trans_Mangle( ::HIR::Path(type.clone(), mv$(gpath), m.first) ) << ",\n";
}
}
- m_of << "\n";
m_of << "\t};\n";
m_mir_res = nullptr;
@@ -2186,6 +2192,21 @@ namespace {
{
return m_options.emulated_i128 && (ty == ::HIR::CoreType::I128 || ty == ::HIR::CoreType::U128);
}
+ // Returns true if the input type is a ZST and ZSTs are not being emitted
+ bool type_is_bad_zst(const ::HIR::TypeRef& ty) const
+ {
+ if( m_options.disallow_empty_structs )
+ {
+ size_t size, align;
+ // NOTE: Uses the Size+Align version because that doesn't panic on unsized
+ MIR_ASSERT(*m_mir_res, Target_GetSizeAndAlignOf(sp, m_resolve, ty, size, align), "Unexpected generic? " << ty);
+ return size == 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt, unsigned indent_level=1)
{
@@ -2259,6 +2280,13 @@ namespace {
m_of << "abort()";
break;
}
+
+ if( ve.is_Field() && this->type_is_bad_zst(ty) )
+ {
+ m_of << "/* ZST field */";
+ break;
+ }
+
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve);
@@ -2317,6 +2345,64 @@ namespace {
special = true;
}
)
+ else {
+ }
+
+ // NOTE: If disallow_empty_structs is set, structs don't include ZST fields
+ // In this case, we need to avoid mentioning the removed fields
+ if( !special && m_options.disallow_empty_structs && ve.val.is_Field() && this->type_is_bad_zst(ty) )
+ {
+ // Work backwards to the first non-ZST field
+ const auto* val_fp = &ve.val.as_Field();
+ while( val_fp->val->is_Field() )
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_lvalue_type(tmp, *val_fp->val);
+ if( !this->type_is_bad_zst(ty) )
+ break;
+ }
+ // Here, we have `val_fp` be a LValue::Field that refers to a ZST, but the inner of the field points to a non-ZST or a local
+
+ emit_lvalue(e.dst);
+ m_of << " = ";
+
+ // If the index is zero, then the best option is to borrow the source
+ if( val_fp->field_index == 0 )
+ {
+ m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ }
+ else
+ {
+ ::HIR::TypeRef tmp;
+ auto tmp_lv = ::MIR::LValue::make_Field({ box$(val_fp->val->clone()), val_fp->field_index - 1 });
+ bool use_parent = false;
+ for(;;)
+ {
+ const auto& ty = mir_res.get_lvalue_type(tmp, tmp_lv);
+ if( !this->type_is_bad_zst(ty) )
+ break;
+ if( tmp_lv.as_Field().field_index == 0 )
+ {
+ use_parent = true;
+ break;
+ }
+ tmp_lv.as_Field().field_index -= 1;
+ }
+
+ // Reached index zero, with still ZST
+ if( use_parent )
+ {
+ m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ }
+ // Use the address after the previous item
+ else
+ {
+ m_of << "(void*)( & "; emit_lvalue(tmp_lv); m_of << " + 1 )";
+ }
+ }
+ special = true;
+ }
+
if( !special )
{
emit_lvalue(e.dst);
@@ -2535,8 +2621,25 @@ namespace {
emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val);
),
(Tuple,
- for(unsigned int j = 0; j < ve.vals.size(); j ++) {
- if( j != 0 ) m_of << ";\n" << indent;
+ bool has_emitted = false;
+ for(unsigned int j = 0; j < ve.vals.size(); j ++)
+ {
+ if( m_options.disallow_empty_structs )
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]);
+
+ if( this->type_is_bad_zst(ty) )
+ {
+ continue ;
+ }
+ }
+
+ if(has_emitted) {
+ m_of << ";\n" << indent;
+ }
+ has_emitted = true;
+
emit_lvalue(e.dst);
m_of << "._" << j << " = ";
emit_param(ve.vals[j]);
@@ -2597,11 +2700,9 @@ namespace {
}
),
(Struct,
- bool is_val_enum = false;
-
if( ve.vals.empty() )
{
- if( m_options.disallow_empty_structs && !is_val_enum)
+ if( m_options.disallow_empty_structs )
{
emit_lvalue(e.dst);
m_of << "._d = 0";
@@ -2609,14 +2710,25 @@ namespace {
}
else
{
+ bool has_emitted = false;
for(unsigned int j = 0; j < ve.vals.size(); j ++)
{
// HACK: Don't emit assignment of PhantomData
::HIR::TypeRef tmp;
- if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) )
+ const auto& ty = mir_res.get_param_type(tmp, ve.vals[j]);
+ if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data(ty) )
continue ;
- if( j != 0 ) m_of << ";\n" << indent;
+ if( this->type_is_bad_zst(ty) )
+ {
+ continue ;
+ }
+
+ if(has_emitted) {
+ m_of << ";\n" << indent;
+ }
+ has_emitted = true;
+
emit_lvalue(e.dst);
m_of << "._" << j << " = ";
emit_param(ve.vals[j]);
@@ -3011,7 +3123,18 @@ namespace {
m_of << "(";
for(unsigned int j = 0; j < e.args.size(); j ++) {
if(j != 0) m_of << ",";
- m_of << " "; emit_param(e.args[j]);
+ m_of << " ";
+ if( m_options.disallow_empty_structs && TU_TEST1(e.args[j], LValue, .is_Field()) )
+ {
+ ::HIR::TypeRef tmp;
+ const auto& ty = m_mir_res->get_param_type(tmp, e.args[j]);
+ if( this->type_is_bad_zst(ty) )
+ {
+ m_of << "{0}";
+ continue;
+ }
+ }
+ emit_param(e.args[j]);
}
m_of << " );\n";
}
@@ -3420,7 +3543,6 @@ namespace {
emit_lvalue(e.ret_val); m_of << " = ";
const auto& ty = params.m_types.at(0);
//TODO: Get the unsized type and use that in place of MetadataType
- #if 1
auto inner_ty = get_inner_unsized_type(ty);
if( inner_ty == ::HIR::TypeRef() ) {
m_of << "sizeof("; emit_ctype(ty); m_of << ")";
@@ -3441,27 +3563,14 @@ namespace {
if( ! ty.m_data.is_TraitObject() ) {
m_of << "sizeof("; emit_ctype(ty); m_of << ") + ";
}
- m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->size";
+ //auto vtable_path = inner_ty.m_data.as_TraitObject().m_trait.m_path.clone();
+ //vtable_path.m_path.m_components.back() += "#vtable";
+ //auto vtable_ty = ::HIR::TypeRef
+ m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->_1";
}
else {
MIR_BUG(mir_res, "Unknown inner unsized type " << inner_ty << " for " << ty);
}
- #else
- switch( metadata_type(ty) )
- {
- case MetadataType::None:
- m_of << "sizeof("; emit_ctype(ty); m_of << ")";
- break;
- case MetadataType::Slice: {
- // TODO: Have a function that fetches the inner type for types like `Path` or `str`
- const auto& ity = *ty.m_data.as_Slice().inner;
- emit_param(e.args.at(0)); m_of << ".META * sizeof("; emit_ctype(ity); m_of << ")";
- break; }
- case MetadataType::TraitObject:
- m_of << "((VTABLE_HDR*)"; emit_param(e.args.at(0)); m_of << ".META)->size";
- break;
- }
- #endif
}
else if( name == "min_align_of_val" ) {
emit_lvalue(e.ret_val); m_of << " = ";
@@ -4243,7 +4352,15 @@ namespace {
switch( metadata_type(ty) )
{
case MetadataType::None:
- m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n";
+
+ if( this->type_is_bad_zst(ty) && slot.is_Field() )
+ {
+ m_of << indent << Trans_Mangle(p) << "((void*)&"; emit_lvalue(*slot.as_Field().val); m_of << ");\n";
+ }
+ else
+ {
+ m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n";
+ }
break;
case MetadataType::Slice:
make_fcn = "make_sliceptr"; if(0)