summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2017-01-20 19:44:47 +0800
committerJohn Hodge <tpg@mutabah.net>2017-01-20 19:44:47 +0800
commit2beb017a0c550a0979129621b826ee3c85fa72a6 (patch)
tree693f46424047a3a6d6b064b9ba7307cfce4ddbf8 /src
parentf095478f874b2122a98d0acd7dd1a59293799a94 (diff)
downloadmrust-2beb017a0c550a0979129621b826ee3c85fa72a6.tar.gz
MIR - Drop flags (incomplete, doesn't pass validation)
Diffstat (limited to 'src')
-rw-r--r--src/hir/deserialise.cpp3
-rw-r--r--src/hir/serialise.cpp6
-rw-r--r--src/mir/check.cpp43
-rw-r--r--src/mir/cleanup.cpp2
-rw-r--r--src/mir/dump.cpp12
-rw-r--r--src/mir/from_hir.cpp4
-rw-r--r--src/mir/from_hir.hpp57
-rw-r--r--src/mir/from_hir_match.cpp20
-rw-r--r--src/mir/mir.hpp11
-rw-r--r--src/mir/mir_builder.cpp656
-rw-r--r--src/mir/optimise.cpp2
-rw-r--r--src/trans/codegen_c.cpp3
-rw-r--r--src/trans/enumerate.cpp4
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);