diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/deserialise.cpp | 3 | ||||
-rw-r--r-- | src/hir/serialise.cpp | 6 | ||||
-rw-r--r-- | src/mir/check.cpp | 43 | ||||
-rw-r--r-- | src/mir/cleanup.cpp | 2 | ||||
-rw-r--r-- | src/mir/dump.cpp | 12 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 4 | ||||
-rw-r--r-- | src/mir/from_hir.hpp | 57 | ||||
-rw-r--r-- | src/mir/from_hir_match.cpp | 20 | ||||
-rw-r--r-- | src/mir/mir.hpp | 11 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 656 | ||||
-rw-r--r-- | src/mir/optimise.cpp | 2 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 3 | ||||
-rw-r--r-- | src/trans/enumerate.cpp | 4 |
13 files changed, 445 insertions, 378 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 11a2a77e..3d94bd44 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -966,7 +966,8 @@ namespace { case 1: return ::MIR::Statement::make_Drop({ m_in.read_bool() ? ::MIR::eDropKind::DEEP : ::MIR::eDropKind::SHALLOW, - deserialise_mir_lvalue() + deserialise_mir_lvalue(), + static_cast<unsigned int>(m_in.read_count()) }); case 2: return ::MIR::Statement::make_Asm({ diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index b568ff46..9092dcab 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -479,6 +479,7 @@ namespace { assert(e.kind == ::MIR::eDropKind::DEEP || e.kind == ::MIR::eDropKind::SHALLOW); m_out.write_bool(e.kind == ::MIR::eDropKind::DEEP); serialise(e.slot); + m_out.write_count(e.flag_idx); ), (Asm, m_out.write_tag(2); @@ -487,6 +488,11 @@ namespace { serialise_vec(e.outputs); serialise_vec(e.clobbers); serialise_vec(e.flags); + ), + (SetDropFlag, + m_out.write_tag(3); + m_out.write_count(e.idx); + m_out.write_bool(e.new_val); ) ) } diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 0dce004e..daaafa6c 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -261,21 +261,28 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } }; ::std::vector< ValStates> block_start_states( fcn.blocks.size() ); - ::std::vector< ::std::pair<unsigned int, ValStates> > to_visit_blocks; + struct ToVisit { + unsigned int bb; + ::std::vector<unsigned int> path; + ValStates state; + }; + ::std::vector<ToVisit> to_visit_blocks; - auto add_to_visit = [&](auto idx, auto vs) { + auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, auto vs) { for(const auto& b : to_visit_blocks) - if( b.first == idx && b.second == vs) + if( b.bb == idx && b.state == vs) return ; if( block_start_states.at(idx) == vs ) return ; - to_visit_blocks.push_back( ::std::make_pair(idx, mv$(vs)) ); + src_path.push_back(idx); + to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); }; - to_visit_blocks.push_back( ::std::make_pair(0, ValStates{ args.size(), fcn.temporaries.size(), fcn.named_variables.size() }) ); + add_to_visit( 0, {}, ValStates { args.size(), fcn.temporaries.size(), fcn.named_variables.size() } ); while( to_visit_blocks.size() > 0 ) { - auto block = to_visit_blocks.back().first; - auto val_state = mv$( to_visit_blocks.back().second ); + auto block = to_visit_blocks.back().bb; + auto path = mv$(to_visit_blocks.back().path); + auto val_state = mv$( to_visit_blocks.back().state ); to_visit_blocks.pop_back(); assert(block < fcn.blocks.size()); @@ -284,6 +291,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path if( ! block_start_states.at(block).merge( val_state ) ) { continue ; } + DEBUG("BB" << block << " via [" << path << "]"); // 2. Using the newly merged state, iterate statements checking the usage and updating state. const auto& bb = fcn.blocks[block]; @@ -296,9 +304,14 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { case ::MIR::Statement::TAGDEAD: throw ""; + case ::MIR::Statement::TAG_SetDropFlag: + break; case ::MIR::Statement::TAG_Drop: // Invalidate the slot - val_state.ensure_valid(state, stmt.as_Drop().slot); + if( stmt.as_Drop().flag_idx == ~0u ) + { + val_state.ensure_valid(state, stmt.as_Drop().slot); + } val_state.mark_validity( state, stmt.as_Drop().slot, false ); break; case ::MIR::Statement::TAG_Asm: @@ -395,7 +408,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ), (Goto, // Push block with the new state - add_to_visit( e, mv$(val_state) ); + add_to_visit( e, mv$(path), mv$(val_state) ); ), (Panic, // What should be done here? @@ -403,14 +416,14 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path (If, // Push blocks val_state.ensure_valid( state, e.cond ); - add_to_visit( e.bb0, val_state ); - add_to_visit( e.bb1, mv$(val_state) ); + add_to_visit( e.bb0, path, val_state ); + add_to_visit( e.bb1, mv$(path), mv$(val_state) ); ), (Switch, val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, val_state ); + add_to_visit( tgt, path, val_state ); } ), (Call, @@ -419,11 +432,11 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path for(const auto& arg : e.args) val_state.ensure_valid( state, arg ); // Push blocks (with return valid only in one) - add_to_visit(e.panic_block, val_state); + add_to_visit(e.panic_block, path, val_state); // TODO: If the function returns !, don't follow the ret_block val_state.mark_validity( state, e.ret_val, true ); - add_to_visit(e.ret_block, mv$(val_state)); + add_to_visit(e.ret_block, mv$(path), mv$(val_state)); ) ) } @@ -445,6 +458,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { case ::MIR::Statement::TAGDEAD: throw ""; + case ::MIR::Statement::TAG_SetDropFlag: + break; case ::MIR::Statement::TAG_Assign: { const auto& a = stmt.as_Assign(); diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index c3f0ba86..53d1c17b 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -924,6 +924,8 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, (Drop, MIR_Cleanup_LValue(state, mutator, se.slot); ), + (SetDropFlag, + ), (Asm, for(auto& v : se.inputs) MIR_Cleanup_LValue(state, mutator, v.second); diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 9669b962..3e688170 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -145,6 +145,10 @@ namespace { { m_os << indent() << "let tmp$" << i << ": " << fcn.temporaries[i] << ";\n"; } + for(unsigned int i = 0; i < fcn.drop_flags.size(); i ++) + { + m_os << indent() << "let df$" << i << " = " << fcn.drop_flags[i] << ";\n"; + } #define FMT_M(x) FMT_CB(os, this->fmt_val(os,x);) for(unsigned int i = 0; i < fcn.blocks.size(); i ++) @@ -179,6 +183,10 @@ namespace { m_os << ")"; for(const auto& v : e.flags) m_os << " \"" << v << "\""; + m_os << ";\n"; + ), + (SetDropFlag, + m_os << "df$" << e.idx << " = " << e.new_val << ";\n"; ), (Drop, DEBUG("- DROP " << e.slot); @@ -191,6 +199,10 @@ namespace { case ::MIR::eDropKind::DEEP: break; } + if( e.flag_idx != ~0u ) + { + m_os << " IF df$" << e.flag_idx; + } m_os << ");\n"; ) ) diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index a9ecc9c2..8e536c76 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -729,8 +729,8 @@ namespace { { m_builder.push_stmt_assign( node.span(), result_val.clone(), m_builder.get_result(node.m_false->span()) ); m_builder.terminate_scope(node.span(), mv$(stmt_scope)); - m_builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); m_builder.end_split_arm(node.span(), scope, true); + m_builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); } else { { auto _ = mv$(stmt_scope); } @@ -741,8 +741,8 @@ namespace { { // Assign `()` to the result m_builder.push_stmt_assign(node.span(), result_val.clone(), ::MIR::RValue::make_Tuple({}) ); - m_builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); m_builder.end_split_arm(node.span(), scope, true); + m_builder.end_block( ::MIR::Terminator::make_Goto(next_block) ); } m_builder.set_cur_block(next_block); m_builder.terminate_scope( node.span(), mv$(scope) ); diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index b644e66f..494e0fa6 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -38,14 +38,14 @@ public: ~ScopeHandle(); }; -// TODO: Replace VarState with a TU -#if 0 +// - Needs to handle future DerefMove (which can't use the Box hack) enum class InvalidType { Uninit, Moved, Descoped, }; -TAGGED_UNION(VarState, Uninit, +// NOTE: If there's a optional move and a partial merging, it becomes a partial? +TAGGED_UNION_EX(VarState, (), Invalid, ( // Currently invalid (Invalid, InvalidType), // Partially valid (Map of field states, Box is assumed to have one field) @@ -53,25 +53,16 @@ TAGGED_UNION(VarState, Uninit, // Optionally valid (integer indicates the drop flag index) (Optional, unsigned int), // Fully valid - (Valid, struct {}), - ) -#endif - -// TODO: Replace the first three states with just one (and flags for init/moved) -enum class VarState { - Uninit, // No value assigned yet - Moved, // Definitely moved - Dropped, // Dropped (out of scope) - - // TODO: Store a bitmap of inner states? - // - Needs to handle relatively arbitary patterns. Including moving out of a Box, but not out of Drop types - InnerMoved, // The inner has been moved, but the container needs to be dropped - //MaybeMovedInner, // Inner possibly has been moved - MaybeMoved, // Possibly has been moved - - Init, // Initialised and valid at this point -}; -extern ::std::ostream& operator<<(::std::ostream& os, VarState x); + (Valid, struct {}) + ), + (), (), + ( + VarState clone() const; + bool operator==(VarState& x) const; + bool operator!=(VarState& x) const { return !(*this == x); } + ) + ); +extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x); struct SplitArm { bool has_early_terminated = false; @@ -79,6 +70,10 @@ struct SplitArm { ::std::map<unsigned int, VarState> var_states; ::std::map<unsigned int, VarState> tmp_states; }; +struct SplitEnd { + ::std::map<unsigned int, VarState> var_states; + ::std::map<unsigned int, VarState> tmp_states; +}; TAGGED_UNION(ScopeType, Variables, (Variables, struct { @@ -88,6 +83,8 @@ TAGGED_UNION(ScopeType, Variables, ::std::vector<unsigned int> temporaries; // Controlled temporaries }), (Split, struct { + bool end_state_valid = false; + SplitEnd end_state; ::std::vector<SplitArm> arms; }), (Loop, struct { @@ -171,11 +168,13 @@ public: // Push an assignment. NOTE: This also marks the rvalue as moved void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val); // Push a drop (likely only used by scope cleanup) - void push_stmt_drop(const Span& sp, ::MIR::LValue val); + void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u); // Push a shallow drop (for Box) void push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val); // Push an inline assembly statement (NOTE: inputs aren't marked as moved) void push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data); + // Pus + void push_stmt_set_dropflag(const Span& sp, unsigned int index, bool value); // - Block management bool block_active() const { @@ -196,6 +195,10 @@ public: ::MIR::BasicBlockId new_bb_linked(); ::MIR::BasicBlockId new_bb_unlinked(); + unsigned int new_drop_flag(bool default_state); + unsigned int new_drop_flag_and_set(const Span& sp, bool set_state); + bool get_drop_flag_default(const Span& sp, unsigned int index); + // --- Scopes --- ScopeHandle new_scope_var(const Span& sp); ScopeHandle new_scope_temp(const Span& sp); @@ -215,10 +218,10 @@ public: // Helper - Marks a variable/... as moved (and checks if the move is valid) void moved_lvalue(const Span& sp, const ::MIR::LValue& lv); private: - VarState get_variable_state(const Span& sp, unsigned int idx) const; - void set_variable_state(const Span& sp, unsigned int idx, VarState state); - VarState get_temp_state(const Span& sp, unsigned int idx) const; - void set_temp_state(const Span& sp, unsigned int idx, VarState state); + const VarState& get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; + VarState& get_variable_state_mut(const Span& sp, unsigned int idx); + const VarState& get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; + VarState& get_temp_state_mut(const Span& sp, unsigned int idx); void drop_scope_values(const ScopeDef& sd); void complete_scope(ScopeDef& sd); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index f5e083bf..0e1a94aa 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -221,19 +221,6 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } }; - bool has_move_pattern = false; - for(const auto& arm : node.m_arms) - { - for(const auto& pat : arm.m_patterns) - { - has_move_pattern |= H::is_pattern_move(node.span(), builder, pat); - if( has_move_pattern ) - break ; - } - if( has_move_pattern ) - break ; - } - auto match_scope = builder.new_scope_split(node.span()); // Map of arm index to ruleset @@ -277,13 +264,6 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } builder.terminate_scope( arm.m_code->span(), mv$(pat_scope) ); - // TODO: If this pattern ignores fields with Drop impls, this will lead to leaks. - // - Ideally, this would trigger a drop of whatever wasn't already taken by the pattern. - if( has_move_pattern ) - { - builder.moved_lvalue(node.span(), match_val); - } - // Condition // NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy // - The above is rustc E0008 "cannot bind by-move into a pattern guard" diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index fb69c7d9..565d159b 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -222,15 +222,15 @@ TAGGED_UNION(Statement, Assign, ::std::vector< ::std::string> flags; }), // Update the state of a drop flag - //(SetDropFlag, struct { - // unsigned int idx; - // bool new_val; - // }), + (SetDropFlag, struct { + unsigned int idx; + bool new_val; + }), // Drop a value (Drop, struct { - //unsigned int flag_idx; // Valid if != ~0u eDropKind kind; // NOTE: For the `box` primitive LValue slot; + unsigned int flag_idx; // Valid if != ~0u }) ); @@ -246,6 +246,7 @@ class Function public: ::std::vector< ::HIR::TypeRef> named_variables; ::std::vector< ::HIR::TypeRef> temporaries; + ::std::vector<bool> drop_flags; ::std::vector<BasicBlock> blocks; }; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 530ee0e9..a3c74ea9 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -32,7 +32,9 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } ); m_scope_stack.push_back( 1 ); - m_variable_states.resize( output.named_variables.size(), VarState::Uninit ); + m_variable_states.reserve( output.named_variables.size() ); + for(unsigned int i = 0; i < output.named_variables.size(); i ++ ) + m_variable_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); } MirBuilder::~MirBuilder() { @@ -103,7 +105,7 @@ void MirBuilder::define_variable(unsigned int idx) DEBUG("DEFINE tmp" << rv << ": " << ty); m_output.temporaries.push_back( ty.clone() ); - m_temporary_states.push_back( VarState::Uninit ); + m_temporary_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); assert(m_output.temporaries.size() == m_temporary_states.size()); ScopeDef* top_scope = nullptr; @@ -253,7 +255,7 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal mark_value_assigned(sp, dst); m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); } -void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val) +void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); @@ -264,7 +266,10 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val) } DEBUG("DROP " << val); - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val) }) ); + + auto stmt = ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val), flag }); + + m_output.blocks.at(m_current_block).statements.push_back( mv$(stmt) ); } void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val) { @@ -278,7 +283,7 @@ void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val) //} DEBUG("DROP shallow " << val); - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val) }) ); + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), ~0u }) ); } void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) { @@ -291,61 +296,60 @@ void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) // 2. Push m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Asm( mv$(data) ) ); } +void MirBuilder::push_stmt_set_dropflag(const Span& sp, unsigned int idx, bool value) +{ + ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); + m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_SetDropFlag({ idx, value }) ); +} void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { + VarState* state_p = nullptr; TU_MATCH_DEF(::MIR::LValue, (dst), (e), ( ), (Temporary, - switch(get_temp_state(sp, e.idx)) + state_p = &get_temp_state_mut(sp, e.idx); + if( const auto* se = state_p->opt_Invalid() ) { - case VarState::Uninit: - break; - case VarState::Dropped: - // ERROR? - break; - case VarState::Moved: - case VarState::MaybeMoved: - // ERROR? Temporaries shouldn't be resassigned after becoming valid - break; - case VarState::InnerMoved: - BUG(sp, "Reassigning inner-moved temporary - " << dst); - break; - case VarState::Init: - // ERROR. Temporaries are single-assignment - break; + if( *se != InvalidType::Uninit ) { + BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); + } + } + else { + // TODO: This should be a bug, but some of the match code ends up reassigning so.. + //BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); } - set_temp_state(sp, e.idx, VarState::Init); ), (Return, // Don't drop. - //m_return_valid = true; + // No state tracking for the return value ), (Variable, // TODO: Ensure that slot is mutable (information is lost, assume true) - switch( get_variable_state(sp, e) ) - { - case VarState::Uninit: - case VarState::Moved: - break; - case VarState::Dropped: - // TODO: Is this an error? The variable has descoped. - break; - case VarState::Init: - // Drop (if not Copy) - Copy check is done within push_stmt_drop + state_p = &get_variable_state_mut(sp, e); + ) + ) + + if( state_p ) + { + TU_MATCHA( (*state_p), (se), + (Invalid, + ASSERT_BUG(sp, se != InvalidType::Descoped, "Assining of descoped variable - " << dst); + ), + (Valid, push_stmt_drop( sp, dst.clone() ); - break; - case VarState::InnerMoved: + ), + (Optional, + push_stmt_drop( sp, dst.clone(), se ); + ), + (Partial, + // TODO: Check type, if Box emit _shallow, otherwise destructure drop push_stmt_drop_shallow( sp, dst.clone() ); - break; - case VarState::MaybeMoved: - // TODO: Conditional drop - break; - } - set_variable_state(sp, e, VarState::Init); + ) ) - ) + *state_p = VarState::make_Valid({}); + } } void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope) @@ -552,6 +556,25 @@ void MirBuilder::end_block(::MIR::Terminator term) return rv; } + +unsigned int MirBuilder::new_drop_flag(bool default_state) +{ + auto rv = m_output.drop_flags.size(); + m_output.drop_flags.push_back(default_state); + DEBUG("(" << default_state << ") = " << rv); + return rv; +} +unsigned int MirBuilder::new_drop_flag_and_set(const Span& sp, bool set_state) +{ + auto rv = new_drop_flag(!set_state); + push_stmt_set_dropflag(sp, rv, set_state); + return rv; +} +bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx) +{ + return m_output.drop_flags.at(idx); +} + ScopeHandle MirBuilder::new_scope_var(const Span& sp) { unsigned int idx = m_scopes.size(); @@ -638,11 +661,11 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, SplitArm sa; for(const auto& i : e.changed_vars) { - sa.var_states.insert( ::std::make_pair(i, get_variable_state(sp, i)) ); + sa.var_states.insert( ::std::make_pair(i, get_variable_state(sp, i).clone()) ); } for(const auto& i : e.changed_tmps) { - sa.tmp_states.insert( ::std::make_pair(i, get_temp_state(sp, i)) ); + sa.tmp_states.insert( ::std::make_pair(i, get_temp_state(sp, i).clone()) ); } e.exit_states.push_back( mv$(sa) ); } @@ -671,6 +694,98 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, } } } + +namespace +{ + static void merge_state(const Span& sp, MirBuilder& builder, const ::MIR::LValue& lv, VarState& old_state, const VarState& new_state) + { + DEBUG(lv << " : " << old_state << " <= " << new_state); + switch(old_state.tag()) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + // Invalid->Invalid :: Choose the highest of the invalid types (TODO) + return ; + case VarState::TAG_Valid: + // Allocate a drop flag + old_state = VarState::make_Optional( builder.new_drop_flag_and_set(sp, true) ); + return ; + case VarState::TAG_Optional: + // Was invalid, now optional. + if( builder.get_drop_flag_default( sp, new_state.as_Optional() ) != false ) { + TODO(sp, "Drop flag default not false when going Invalid->Optional"); + } + old_state = VarState::make_Optional( new_state.as_Optional() ); + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Invalid->Partial in split scope"); + } + break; + case VarState::TAG_Valid: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + old_state = VarState::make_Optional( builder.new_drop_flag_and_set(sp, false) ); + return ; + case VarState::TAG_Valid: + return ; + case VarState::TAG_Optional: + // Was valid, now optional. + if( builder.get_drop_flag_default( sp, new_state.as_Optional() ) != true ) { + TODO(sp, "Drop flag default not true when going Valid->Optional"); + } + old_state = VarState::make_Optional( new_state.as_Optional() ); + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Valid->Partial in split scope"); + } + break; + case VarState::TAG_Optional: + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), false); + return ; + case VarState::TAG_Valid: + builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), true); + return ; + case VarState::TAG_Optional: + if( old_state.as_Optional() != new_state.as_Optional() ) { + TODO(sp, "Handle Optional->Optional with mismatched flags"); + } + return ; + case VarState::TAG_Partial: + TODO(sp, "Handle Optional->Partial in split scope"); + } + break; + case VarState::TAG_Partial: + // Need to tag for conditional shallow drop? Or just do that at the end of the split? + // - End of the split means that the only optional state is outer drop. + switch( new_state.tag() ) + { + case VarState::TAGDEAD: throw ""; + case VarState::TAG_Invalid: + TODO(sp, "Handle Partial->Invalid in split scope"); + case VarState::TAG_Valid: + TODO(sp, "Handle Partial->Valid in split scope"); + case VarState::TAG_Optional: + TODO(sp, "Handle Partial->Optional in split scope"); + case VarState::TAG_Partial: + ASSERT_BUG(sp, old_state.as_Partial().size() == new_state.as_Partial().size(), "Partial->Partial with mismatchd sizes"); + TODO(sp, "Handle Partial->Partial in split scope"); + } + break; + } + BUG(sp, "Unhandled combination - " << old_state.tag_str() << " and " << new_state.tag_str()); + } +} + void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable) { ASSERT_BUG(sp, handle.idx < m_scopes.size(), ""); @@ -680,27 +795,66 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r ASSERT_BUG(sp, !sd_split.arms.empty(), ""); TRACE_FUNCTION_F("end split scope " << handle.idx << " arm " << (sd_split.arms.size()-1)); + if( reachable ) + ASSERT_BUG(sp, m_block_active, "Block must be active when ending a reachable split arm"); - sd_split.arms.back().always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; + auto& this_arm_state = sd_split.arms.back(); + this_arm_state.always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; - // HACK: If this arm's end is reachable, convert InnerMoved (shallow drop) variable states to Moved - // - I'm not 100% sure this is the correct place for calling drop. - #if 1 - if( reachable ) + if( sd_split.end_state_valid ) { - for(auto& vse : sd_split.arms.back().var_states) + if( reachable ) { - //auto i = vse.first; - auto& vs = vse.second; - if( vs == VarState::InnerMoved ) { - // TODO: Refactor InnerMoved to handle partial moves via Box - // Emit the shallow drop - //push_stmt_drop_shallow( sp, ::MIR::LValue::make_Variable(i) ); - vs = VarState::Moved; + // Insert copies of the parent state + for(const auto& ent : this_arm_state.var_states) { + if( sd_split.end_state.var_states.count(ent.first) == 0 ) { + sd_split.end_state.var_states.insert(::std::make_pair( ent.first, get_variable_state(sp, ent.first, 1).clone() )); + } + } + for(const auto& ent : this_arm_state.tmp_states) { + if( sd_split.end_state.tmp_states.count(ent.first) == 0 ) { + sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, get_temp_state(sp, ent.first, 1).clone() )); + } + } + + // Merge state + for(auto& ent : sd_split.end_state.var_states) + { + auto idx = ent.first; + auto& out_state = ent.second; + + // Merge the states + auto it = this_arm_state.var_states.find(idx); + const auto& src_state = (it != this_arm_state.var_states.end() ? it->second : get_variable_state(sp, idx, 1)); + + merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), out_state, src_state); + } + for(auto& ent : sd_split.end_state.tmp_states) + { + auto idx = ent.first; + auto& out_state = ent.second; + + // Merge the states + auto it = this_arm_state.tmp_states.find(idx); + const auto& src_state = (it != this_arm_state.tmp_states.end() ? it->second : get_temp_state(sp, idx, 1)); + + merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state); } } } - #endif + else + { + // Clone this arm's state + for(auto& ent : this_arm_state.var_states) + { + sd_split.end_state.var_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } + for(auto& ent : this_arm_state.tmp_states) + { + sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } + sd_split.end_state_valid = true; + } sd_split.arms.push_back( {} ); } @@ -725,112 +879,7 @@ void MirBuilder::end_split_arm_early(const Span& sp) auto& sd_split = sd.data.as_Split(); sd_split.arms.back().has_early_terminated = true; - for(const auto& vse : sd_split.arms.back().var_states) - { - auto i = vse.first; - const auto& vs = vse.second; - if( vs == VarState::InnerMoved ) { - // Emit the shallow drop - push_stmt_drop_shallow( sp, ::MIR::LValue::make_Variable(i) ); - // - Don't update the state, because this drop isn't the end-of-scope drop - } - } - } -} -namespace { - static VarState merge_state(const Span& sp, VarState new_state, VarState old_state) - { - switch(old_state) - { - case VarState::Uninit: - switch( new_state ) - { - case VarState::Uninit: - //BUG(sp, "Variable state changed from Uninit to Uninit (wut?)"); - return VarState::Uninit; - case VarState::Init: - // TODO: MaybeInit? - return VarState::MaybeMoved; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::Uninit; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (wa Uninit)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - BUG(sp, "Override from Uninit to " << new_state); - break; - case VarState::Init: - switch( new_state ) - { - case VarState::Uninit: - // TODO: MaybeInit? - return VarState::MaybeMoved; - case VarState::Init: - return VarState::Init; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::MaybeMoved; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (was Init)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - break; - case VarState::InnerMoved: - // Need to tag for conditional shallow drop? Or just do that at the end of the split? - // - End of the split means that the only optional state is outer drop. - switch( new_state ) - { - case VarState::Uninit: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Uninit"); - case VarState::Init: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Init"); - case VarState::MaybeMoved: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now MaybeMoved"); - case VarState::Moved: - TODO(sp, "Handle InnerMoved in Split scope (new_states) - Now Moved"); - case VarState::InnerMoved: - return VarState::InnerMoved; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - } - break; - case VarState::MaybeMoved: - // Already optional, don't change - return VarState::MaybeMoved; - case VarState::Moved: - switch( new_state ) - { - case VarState::Uninit: - return VarState::Moved; - case VarState::Init: - // Wut? Reinited? - return VarState::MaybeMoved; - case VarState::MaybeMoved: - return VarState::MaybeMoved; - case VarState::Moved: - return VarState::Moved; - case VarState::InnerMoved: - TODO(sp, "Handle InnerMoved in Split scope (was Moved)"); - break; - case VarState::Dropped: - BUG(sp, "Dropped value in arm"); - break; - } - break; - case VarState::Dropped: - TODO(sp, "How can an arm drop a value?"); - break; - } - BUG(sp, "Unhandled combination"); + // TODO: Create drop flags if required? } } void MirBuilder::complete_scope(ScopeDef& sd) @@ -850,100 +899,31 @@ void MirBuilder::complete_scope(ScopeDef& sd) (Split, ) ) - - struct H - { - static void apply_split_arms(MirBuilder& self, const Span& sp, ::std::vector<SplitArm>& arms) - { - // 1. Make a bitmap of changed states in all arms - // 2. Build up the final composite state of the first arm - ::std::map<unsigned int, VarState> new_var_states; - ::std::map<unsigned int, VarState> new_tmp_states; - const SplitArm* first_arm = nullptr; - for(const auto& arm : arms) - { - if( arm.always_early_terminated ) - continue ; - for(const auto& vse : arm.var_states) - { - auto i = vse.first; - if( new_var_states.count(i) == 0 ) - new_var_states.insert( ::std::make_pair(i, vse.second) ); - } - for(const auto& vse : arm.tmp_states) - { - auto i = vse.first; - if( new_tmp_states.count(i) == 0 ) - new_tmp_states.insert( ::std::make_pair(i, vse.second) ); - } - if( !first_arm ) - first_arm = &arm; - } - - if( !first_arm ) - { - DEBUG("No arms yeilded"); - return ; - } - - // 3. Compare the rest of the arms - for(const auto& arm : arms) - { - if( arm.always_early_terminated ) - continue ; - DEBUG("><"); - for(auto& se : new_var_states) - { - auto i = se.first; - DEBUG("- VAR" << i); - auto new_state = (arm.var_states.count(i) != 0 ? arm.var_states.at(i) : self.get_variable_state(sp, i)); - se.second = merge_state(sp, new_state, se.second); - } - for(auto& se : new_tmp_states) - { - auto i = se.first; - DEBUG("- TMP" << i); - auto new_state = (arm.tmp_states.count(i) != 0 ? arm.tmp_states.at(i) : self.get_temp_state(sp, i)); - se.second = merge_state(sp, new_state, se.second); - } - } - - // 4. Apply changes - for(const auto& se : new_var_states) - { - auto i = se.first; - auto new_state = se.second; - DEBUG("var" << i << " old_state = " << self.get_variable_state(sp, i) << ", new_state = " << new_state); - self.set_variable_state(sp, i, new_state); - } - for(const auto& se : new_tmp_states) - { - auto i = se.first; - auto new_state = se.second; - DEBUG("tmp" << i << " old_state = " << self.get_temp_state(sp, i) << ", new_state = " << new_state); - self.set_temp_state(sp, i, new_state); - } - } - }; - // No macro for better debug output. if( sd.data.is_Loop() ) { + #if 0 auto& e = sd.data.as_Loop(); TRACE_FUNCTION_F("Loop - " << e.exit_states.size() << " breaks"); // Merge all exit states and apply to output H::apply_split_arms(*this, sd.span, e.exit_states); + #endif } else if( sd.data.is_Split() ) { auto& e = sd.data.as_Split(); - - assert( e.arms.size() > 1 ); TRACE_FUNCTION_F("Split - " << (e.arms.size() - 1) << " arms"); - e.arms.pop_back(); - H::apply_split_arms(*this, sd.span, e.arms); + ASSERT_BUG(sd.span, e.end_state_valid, ""); + for(auto& ent : e.end_state.var_states) + { + auto& vs = get_variable_state_mut(sd.span, ent.first); + if( vs != ent.second ) + { + vs = ::std::move(ent.second); + } + } } } @@ -1130,7 +1110,7 @@ bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const return rv == 2; } -VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const +const VarState& MirBuilder::get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count) const { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1150,7 +1130,10 @@ VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const auto it = cur_arm.var_states.find(idx); if( it != cur_arm.var_states.end() ) { - return it->second; + if( ! skip_count -- ) + { + return it->second; + } } ) ) @@ -1159,7 +1142,7 @@ VarState MirBuilder::get_variable_state(const Span& sp, unsigned int idx) const ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); return m_variable_states[idx]; } -void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState state) +VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx) { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1176,8 +1159,10 @@ void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState s { auto& e = scope_def.data.as_Split(); auto& cur_arm = e.arms.back(); - cur_arm.var_states[idx] = state; - return ; + auto it = cur_arm.var_states.find(idx); + if( it == cur_arm.var_states.end() ) + return cur_arm.var_states[idx] = get_variable_state(sp, idx).clone(); + return it->second; } else if( scope_def.data.is_Loop() ) { @@ -1190,9 +1175,9 @@ void MirBuilder::set_variable_state(const Span& sp, unsigned int idx, VarState s } ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - m_variable_states[idx] = state; + return m_variable_states[idx]; } -VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const +const VarState& MirBuilder::get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count) const { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1212,7 +1197,10 @@ VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const auto it = cur_arm.tmp_states.find(idx); if( it != cur_arm.tmp_states.end() ) { - return it->second; + if( ! skip_count -- ) + { + return it->second; + } } } } @@ -1220,7 +1208,7 @@ VarState MirBuilder::get_temp_state(const Span& sp, unsigned int idx) const ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); return m_temporary_states[idx]; } -void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state) +VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx) { for( auto scope_idx : ::reverse(m_scope_stack) ) { @@ -1237,8 +1225,10 @@ void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state { auto& e = scope_def.data.as_Split(); auto& cur_arm = e.arms.back(); - cur_arm.tmp_states[idx] = state; - return ; + auto it = cur_arm.tmp_states.find(idx); + if(it == cur_arm.tmp_states.end()) + return cur_arm.tmp_states[idx] = get_temp_state(sp, idx).clone(); + return it->second; } else if( scope_def.data.is_Loop() ) { @@ -1251,7 +1241,7 @@ void MirBuilder::set_temp_state(const Span& sp, unsigned int idx, VarState state } ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - m_temporary_states[idx] = state; + return m_temporary_states[idx]; } void MirBuilder::drop_scope_values(const ScopeDef& sd) @@ -1260,52 +1250,41 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd) (Temporaries, for(auto tmp_idx : ::reverse(e.temporaries)) { - switch( get_temp_state(sd.span, tmp_idx) ) - { - case VarState::Uninit: - DEBUG("Temporary " << tmp_idx << " Uninit"); - break; - case VarState::Dropped: - DEBUG("Temporary " << tmp_idx << " Dropped"); - break; - case VarState::Moved: - DEBUG("Temporary " << tmp_idx << " Moved"); - break; - case VarState::Init: + const auto& vs = get_temp_state(sd.span, tmp_idx); + TU_MATCHA( (vs), (vse), + (Invalid, + ), + (Valid, push_stmt_drop( sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }) ); - //set_temp_state(sd.span, tmp_idx, VarState::Dropped); - break; - case VarState::InnerMoved: + ), + (Partial, + // TODO: Actual destructuring push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }) ); - //set_temp_state(sd.span, tmp_idx, VarState::Dropped); - break; - case VarState::MaybeMoved: - //BUG(sd.span, "Optionally moved temporary? - " << tmp_idx); - break; - } + ), + (Optional, + push_stmt_drop(sd.span, ::MIR::LValue::make_Temporary({ tmp_idx }), vse); + ) + ) } ), (Variables, for(auto var_idx : ::reverse(e.vars)) { - switch( get_variable_state(sd.span, var_idx) ) - { - case VarState::Uninit: - case VarState::Dropped: - case VarState::Moved: - break; - case VarState::Init: + const auto& vs = get_variable_state(sd.span, var_idx); + TU_MATCHA( (vs), (vse), + (Invalid, + ), + (Valid, push_stmt_drop( sd.span, ::MIR::LValue::make_Variable(var_idx) ); - break; - case VarState::InnerMoved: + ), + (Partial, + // TODO: Actual destructuring push_stmt_drop_shallow( sd.span, ::MIR::LValue::make_Variable(var_idx) ); - //set_variable_state(sd.span, var_idx, VarState::Dropped); - break; - case VarState::MaybeMoved: - // TODO: Drop flags - //push_stmt_drop_opt(sd.span, ::MIR::LValue::make_Variable(var_idx), drop_flag_idx); - break; - } + ), + (Optional, + push_stmt_drop(sd.span, ::MIR::LValue::make_Variable(var_idx), vse); + ) + ) } ), (Split, @@ -1323,12 +1302,12 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv) TU_MATCHA( (lv), (e), (Variable, if( !lvalue_is_copy(sp, lv) ) { - set_variable_state(sp, e, VarState::Moved); + get_variable_state_mut(sp, e) = VarState::make_Invalid(InvalidType::Moved); } ), (Temporary, if( !lvalue_is_copy(sp, lv) ) { - set_temp_state(sp, e.idx, VarState::Moved); + get_temp_state_mut(sp, e.idx) = VarState::make_Invalid(InvalidType::Moved); } ), (Argument, @@ -1381,15 +1360,17 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv) ) ) // 2. Mark the slot as requiring only a shallow drop + ::std::vector<VarState> ivs; + ivs.push_back(VarState::make_Invalid(InvalidType::Moved)); TU_MATCH_DEF( ::MIR::LValue, (inner_lv), (ei), ( BUG(sp, "Box move out of invalid LValue " << inner_lv << " - should have been moved"); ), (Variable, - set_variable_state(sp, ei, VarState::InnerMoved); + get_variable_state_mut(sp, ei) = VarState::make_Partial(mv$(ivs)); ), (Temporary, - set_temp_state(sp, ei.idx, VarState::InnerMoved); + get_temp_state_mut(sp, ei.idx) = VarState::make_Partial(mv$(ivs)); ), (Argument, TODO(sp, "Mark arg " << ei.idx << " for shallow drop"); @@ -1449,18 +1430,75 @@ ScopeHandle::~ScopeHandle() } } -::std::ostream& operator<<(::std::ostream& os, VarState x) +VarState VarState::clone() const { - switch(x) - { - #define _(V) case VarState::V: os << #V; break; - _(Uninit) - _(Init) - _(MaybeMoved) - _(Moved) - _(InnerMoved) - _(Dropped) - #undef _ - } + TU_MATCHA( (*this), (e), + (Invalid, + return VarState(e); + ), + (Valid, + return VarState(e); + ), + (Optional, + return VarState(e); + ), + (Partial, + ::std::vector<VarState> n; + n.reserve(e.size()); + for(const auto& a : e) + n.push_back( a.clone() ); + return VarState(mv$(n)); + ) + ) + throw ""; +} +bool VarState::operator==(VarState& x) const +{ + if( this->tag() != x.tag() ) + return false; + TU_MATCHA( (*this, x), (te, xe), + (Invalid, + return te == xe; + ), + (Valid, + return true; + ), + (Optional, + return te == xe; + ), + (Partial, + if( te.size() != xe.size() ) + return false; + for(unsigned int i = 0; i < te.size(); i ++) + { + if( te[i] != xe[i] ) + return false; + } + return true; + ) + ) + throw ""; +} +::std::ostream& operator<<(::std::ostream& os, const VarState& x) +{ + TU_MATCHA( (x), (e), + (Invalid, + switch(e) + { + case InvalidType::Uninit: os << "Uninit"; break; + case InvalidType::Moved: os << "Moved"; break; + case InvalidType::Descoped: os << "Descoped"; break; + } + ), + (Valid, + os << "Valid"; + ), + (Optional, + os << "Optional(" << e << ")"; + ), + (Partial, + os << "Partial(" << e << ")"; + ) + ) return os; } diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 5c94eb77..a0e3ef45 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -148,6 +148,8 @@ namespace { for(auto& v : e.outputs) rv |= visit_mir_lvalue_mut(v.second, true, cb); ), + (SetDropFlag, + ), (Drop, rv |= visit_mir_lvalue_mut(e.slot, false, cb); ) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 21f5113d..ea3ef2d5 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1183,6 +1183,9 @@ namespace { switch( stmt.tag() ) { case ::MIR::Statement::TAGDEAD: throw ""; + case ::MIR::Statement::TAG_SetDropFlag: { + MIR_TODO(mir_res, "SetDropFlag"); + break; } case ::MIR::Statement::TAG_Drop: { const auto& e = stmt.as_Drop(); ::HIR::TypeRef tmp; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 435a68af..593cd6e1 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -824,6 +824,8 @@ void Trans_Enumerate_Types(EnumState& state) (Drop, H::visit_lvalue(tv,pp,fcn, se.slot); ), + (SetDropFlag, + ), (Asm, for(const auto& v : se.outputs) H::visit_lvalue(tv,pp,fcn, v.second); @@ -1397,6 +1399,8 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, for(const auto& v : se.outputs) Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp); ), + (SetDropFlag, + ), (Drop, DEBUG("- DROP " << se.slot); Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot, pp); |