--- /dev/null
+// CS0165: Use of unassigned local variable `u'
+// Line: 15
+
+class X
+{
+ public static void Main ()
+ {
+ int i = 0;
+ int u;
+ switch (i) {
+ case 1:
+ A1:
+ goto case 2;
+ case 2:
+ i = u;
+ goto case 3;
+ case 3:
+ goto case 4;
+ case 4:
+ goto A1;
+ }
+ }
+}
\ No newline at end of file
public DefiniteAssignmentBitSet DefiniteAssignmentOnFalse { get; set; }
- public List<LabeledStatement> LabelStack { get; set; }
+ Dictionary<Statement, List<DefiniteAssignmentBitSet>> LabelStack { get; set; }
public ParametersBlock ParametersBlock { get; set; }
public bool UnreachableReported { get; set; }
+ public bool AddReachedLabel (Statement label)
+ {
+ List<DefiniteAssignmentBitSet> das;
+ if (LabelStack == null) {
+ LabelStack = new Dictionary<Statement, List<DefiniteAssignmentBitSet>> ();
+ das = null;
+ } else {
+ LabelStack.TryGetValue (label, out das);
+ }
+
+ if (das == null) {
+ das = new List<DefiniteAssignmentBitSet> ();
+ das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
+ LabelStack.Add (label, das);
+ return false;
+ }
+
+ foreach (var existing in das) {
+ if (DefiniteAssignmentBitSet.AreEqual (existing, DefiniteAssignment))
+ return true;
+ }
+
+ if (DefiniteAssignment == DefiniteAssignmentBitSet.Empty)
+ das.Add (DefiniteAssignment);
+ else
+ das.Add (new DefiniteAssignmentBitSet (DefiniteAssignment));
+
+ return false;
+ }
+
public DefiniteAssignmentBitSet BranchDefiniteAssignment ()
{
- var dat = DefiniteAssignment;
- if (dat != DefiniteAssignmentBitSet.Empty)
- DefiniteAssignment = new DefiniteAssignmentBitSet (dat);
- return dat;
+ return BranchDefiniteAssignment (DefiniteAssignment);
+ }
+
+ public DefiniteAssignmentBitSet BranchDefiniteAssignment (DefiniteAssignmentBitSet da)
+ {
+ if (da != DefiniteAssignmentBitSet.Empty) {
+ DefiniteAssignment = new DefiniteAssignmentBitSet (da);
+ }
+
+ return da;
}
public void BranchConditionalAccessDefiniteAssignment ()
var expr_true = fc.DefiniteAssignmentOnTrue;
var expr_false = fc.DefiniteAssignmentOnFalse;
- fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
+ fc.BranchDefiniteAssignment (expr_true);
true_expr.FlowAnalysis (fc);
var true_fc = fc.DefiniteAssignment;
- fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
+ fc.BranchDefiniteAssignment (expr_false);
false_expr.FlowAnalysis (fc);
fc.DefiniteAssignment &= true_fc;
large_bits[index >> 5] |= (1 << (index & 31));
}
- static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
+ public static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
{
if (a.large_bits == null)
return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
{
- if (fc.LabelStack == null) {
- fc.LabelStack = new List<LabeledStatement> ();
- } else if (fc.LabelStack.Contains (label)) {
+ if (fc.AddReachedLabel (label))
return true;
- }
- fc.LabelStack.Add (label);
label.Block.ScanGotoJump (label, fc);
- fc.LabelStack.Remove (label);
return true;
}
bool DoFlowAnalysis (FlowAnalysisContext fc, int startIndex)
{
bool end_unreachable = !reachable;
+ bool goto_flow_analysis = startIndex != 0;
for (; startIndex < statements.Count; ++startIndex) {
var s = statements[startIndex];
// this for flow-analysis only to carry variable info correctly.
//
if (end_unreachable) {
+ bool after_goto_case = goto_flow_analysis && s is GotoCase;
+
for (++startIndex; startIndex < statements.Count; ++startIndex) {
s = statements[startIndex];
if (s is SwitchLabel) {
- s.FlowAnalysis (fc);
+ if (!after_goto_case)
+ s.FlowAnalysis (fc);
+
break;
}
statements [startIndex] = RewriteUnreachableStatement (s);
}
}
+
+ //
+ // Idea is to stop after goto case because goto case will always have at least same
+ // variable assigned as switch case label. This saves a lot for complex goto case tests
+ //
+ if (after_goto_case)
+ break;
+
+ continue;
}
+
+ var lb = s as LabeledStatement;
+ if (lb != null && fc.AddReachedLabel (lb))
+ break;
}
//
// L:
// v = 1;
- if (s is BlockVariable)
+ if (s is BlockVariable || s is EmptyStatement)
return s;
return new EmptyStatement (s.loc);
if (!SectionStart)
return false;
- fc.DefiniteAssignment = new DefiniteAssignmentBitSet (fc.SwitchInitialDefinitiveAssignment);
+ fc.BranchDefiniteAssignment (fc.SwitchInitialDefinitiveAssignment);
return false;
}
DefiniteAssignmentBitSet try_fc = res ? null : fc.DefiniteAssignment;
foreach (var c in clauses) {
- fc.DefiniteAssignment = new DefiniteAssignmentBitSet (start_fc);
+ fc.BranchDefiniteAssignment (start_fc);
if (!c.FlowAnalysis (fc)) {
if (try_fc == null)
try_fc = fc.DefiniteAssignment;