summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2017-07-02 18:34:34 +0800
committerJohn Hodge <tpg@ucc.asn.au>2017-07-02 18:34:34 +0800
commitb7bb1f4f9c918e128f7ad83476790830c3f98c4d (patch)
treea48a989aff0bef394dd389089f9274f76dfc4649
parent11d2a7732c5d1c53aee384b2ca4fdc672c2cc1ae (diff)
downloadmrust-b7bb1f4f9c918e128f7ad83476790830c3f98c4d.tar.gz
MIR Gen - Make mutating state (other than the if condition) within a match guard an error
-rw-r--r--src/mir/from_hir.hpp6
-rw-r--r--src/mir/from_hir_match.cpp3
-rw-r--r--src/mir/mir_builder.cpp25
3 files changed, 33 insertions, 1 deletions
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 11a18a6d..b11a380a 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -103,6 +103,11 @@ TAGGED_UNION(ScopeType, Owning,
::std::map<unsigned int,VarState> changed_args;
bool exit_state_valid;
SplitEnd exit_state;
+ }),
+ // State which should end up with no mutation of variable states
+ (Freeze, struct {
+ //::std::map<unsigned int,VarState> changed_slots;
+ //::std::map<unsigned int,VarState> changed_args;
})
);
@@ -257,6 +262,7 @@ public:
ScopeHandle new_scope_temp(const Span& sp);
ScopeHandle new_scope_split(const Span& sp);
ScopeHandle new_scope_loop(const Span& sp);
+ ScopeHandle new_scope_freeze(const Span& sp);
/// Raises every variable defined in the source scope into the target scope
void raise_all(const Span& sp, ScopeHandle src, const ScopeHandle& target);
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index cbb39b34..c10f170b 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -372,17 +372,18 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod
ac.cond_start = builder.new_bb_unlinked();
builder.set_cur_block( ac.cond_start );
+ auto freeze_scope = builder.new_scope_freeze(arm.m_cond->span());
auto tmp_scope = builder.new_scope_temp(arm.m_cond->span());
conv.visit_node_ptr( arm.m_cond );
auto cond_lval = builder.get_result_in_if_cond(arm.m_cond->span());
builder.terminate_scope( arm.m_code->span(), mv$(tmp_scope) );
ac.cond_false = builder.new_bb_unlinked();
builder.end_block(::MIR::Terminator::make_If({ mv$(cond_lval), ac.code, ac.cond_false }));
- // TODO: Emit the `if` (to new blocks) and insert an early termination of the this split arm
builder.set_cur_block(ac.cond_false);
builder.end_split_arm(arm.m_cond->span(), match_scope, true, true);
builder.pause_cur_block();
+ builder.terminate_scope( arm.m_code->span(), mv$(freeze_scope) );
// NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 54269144..5dcb2ed2 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -745,6 +745,14 @@ ScopeHandle MirBuilder::new_scope_loop(const Span& sp)
DEBUG("START (loop) scope " << idx);
return ScopeHandle { *this, idx };
}
+ScopeHandle MirBuilder::new_scope_freeze(const Span& sp)
+{
+ unsigned int idx = m_scopes.size();
+ m_scopes.push_back( ScopeDef {sp, ScopeType::make_Freeze({})} );
+ m_scope_stack.push_back( idx );
+ DEBUG("START (freeze) scope " << idx);
+ return ScopeHandle { *this, idx };
+}
void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cleanup/*=true*/)
{
TRACE_FUNCTION_F("DONE scope " << scope.idx << " - " << (emit_cleanup ? "CLEANUP" : "NO CLEANUP"));
@@ -1510,6 +1518,9 @@ void MirBuilder::complete_scope(ScopeDef& sd)
DEBUG("Loop");
),
(Split,
+ ),
+ (Freeze,
+ //DEBUG("Freeze");
)
)
@@ -1886,6 +1897,18 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
}
+ else if( scope_def.data.is_Freeze() )
+ {
+ if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() )
+ {
+ }
+ else
+ {
+ // NOTE: This is only used in match conditions
+ DEBUG("Mutating state of ?" << idx);
+ ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed");
+ }
+ }
else
{
}
@@ -2159,6 +2182,8 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
),
(Loop,
// No values
+ ),
+ (Freeze,
)
)
}