X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fstatement.cs;h=5fe7e02470cb4aaf593ddac59a3412f867db8158;hb=bd316288ae3fa0cb6f03b367716d04d5244c5d04;hp=bdd2fbb8f3436307ff272c18c7bc89fac01e382e;hpb=7a464d1ac24896e9fafa3aa26040ed6c0522d454;p=mono.git diff --git a/mcs/gmcs/statement.cs b/mcs/gmcs/statement.cs index bdd2fbb8f34..5fe7e02470c 100644 --- a/mcs/gmcs/statement.cs +++ b/mcs/gmcs/statement.cs @@ -14,10 +14,10 @@ using System.Text; using System.Reflection; using System.Reflection.Emit; using System.Diagnostics; +using System.Collections; +using System.Collections.Specialized; namespace Mono.CSharp { - - using System.Collections; public abstract class Statement { public Location loc; @@ -80,7 +80,7 @@ namespace Mono.CSharp { public void Error (int error, string s) { - if (!Location.IsNull (loc)) + if (!loc.IsNull) Report.Error (error, loc, s); else Report.Error (error, s); @@ -410,7 +410,7 @@ namespace Mono.CSharp { Expression Test; readonly Statement InitStatement; readonly Statement Increment; - readonly Statement Statement; + public readonly Statement Statement; bool infinite, empty; public For (Statement initStatement, @@ -527,10 +527,10 @@ namespace Mono.CSharp { public class StatementExpression : Statement { ExpressionStatement expr; - public StatementExpression (ExpressionStatement expr, Location l) + public StatementExpression (ExpressionStatement expr) { this.expr = expr; - loc = l; + loc = expr.Location; } public override bool Resolve (EmitContext ec) @@ -800,21 +800,24 @@ namespace Mono.CSharp { if (expr == null) return false; - if (!(expr is Constant)){ + Constant c = expr as Constant; + if (c == null) { Error (150, "A constant value is expected"); return false; } - object val = Expression.ConvertIntLiteral ( - (Constant) expr, ec.Switch.SwitchType, loc); + c = c.ToType (ec.Switch.SwitchType, loc); + if (c == null) + return false; + object val = c.GetValue (); if (val == null) - return false; + val = c; sl = (SwitchLabel) ec.Switch.Elements [val]; if (sl == null){ - Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", val); + Report.Error (159, loc, "No such label `case {0}:' within the scope of the goto statement", c.GetValue () == null ? "null" : val); return false; } @@ -947,7 +950,7 @@ namespace Mono.CSharp { public override bool Resolve (EmitContext ec) { - if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){ + if (!ec.CurrentBranching.InLoop ()){ Error (139, "No enclosing loop out of which to break or continue"); return false; } else if (ec.InFinally) { @@ -1459,29 +1462,57 @@ namespace Mono.CSharp { public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { - LocalInfo kvi = GetKnownVariableInfo (name); - if (kvi == null || kvi.Block == this) + Block b = this; + LocalInfo kvi = b.GetKnownVariableInfo (name); + while (kvi == null) { + while (b.Implicit) + b = b.Parent; + b = b.Parent; + if (b == null) + return true; + kvi = b.GetKnownVariableInfo (name); + } + + if (kvi.Block == b) return true; - if (known_variables != kvi.Block.known_variables) { - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); - return false; + // Is kvi.Block nested inside 'b' + if (b.known_variables != kvi.Block.known_variables) { + // + // If a variable by the same name it defined in a nested block of this + // block, we violate the invariant meaning in a block. + // + if (b == this) { + Report.SymbolRelatedToPreviousError (kvi.Location, name); + Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); + return false; + } + + // + // It's ok if the definition is in a nested subblock of b, but not + // nested inside this block -- a definition in a sibling block + // should not affect us. + // + return true; } // - // this block and kvi.Block are the same textual block. + // Block 'b' and kvi.Block are the same textual block. // However, different variables are extant. // // Check if the variable is in scope in both blocks. We use // an indirect check that depends on AddVariable doing its // part in maintaining the invariant-meaning-in-block property. // - if (e is LocalVariableReference || (e is Constant && GetLocalInfo (name) != null)) + if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; - Report.SymbolRelatedToPreviousError (kvi.Location, name); - Error_AlreadyDeclared (loc, name, "parent or current"); + // + // Even though we detected the error when the name is used, we + // treat it as if the variable declaration was in error. + // + Report.SymbolRelatedToPreviousError (loc, name); + Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; } @@ -1730,11 +1761,9 @@ namespace Mono.CSharp { continue; } - if (e.Type != variable_type){ - e = Const.ChangeType (vi.Location, ce, variable_type); - if (e == null) - continue; - } + e = ce.ToType (variable_type, vi.Location); + if (e == null) + continue; constants.Remove (name); constants.Add (name, e); @@ -1828,6 +1857,36 @@ namespace Mono.CSharp { bool unreachable_shown; bool unreachable; + private void CheckPossibleMistakenEmptyStatement (Statement s) + { + Statement body; + + // Some statements are wrapped by a Block. Since + // others' internal could be changed, here I treat + // them as possibly wrapped by Block equally. + Block b = s as Block; + if (b != null && b.statements.Count == 1) + s = (Statement) b.statements [0]; + + if (s is Lock) + body = ((Lock) s).Statement; + else if (s is For) + body = ((For) s).Statement; + else if (s is Foreach) + body = ((Foreach) s).Statement; + else if (s is While) + body = ((While) s).Statement; + else if (s is Using) + body = ((Using) s).Statement; + else if (s is Fixed) + body = ((Fixed) s).Statement; + else + return; + + if (body == null || body is EmptyStatement) + Report.Warning (642, 3, s.loc, "Possible mistaken empty statement"); + } + public override bool Resolve (EmitContext ec) { Block prev_block = ec.CurrentBlock; @@ -1849,6 +1908,11 @@ namespace Mono.CSharp { int statement_count = statements.Count; for (int ix = 0; ix < statement_count; ix++){ Statement s = (Statement) statements [ix]; + // Check possible empty statement (CS0642) + if (RootContext.WarningLevel >= 3 && + ix + 1 < statement_count && + statements [ix + 1] is Block) + CheckPossibleMistakenEmptyStatement (s); if (unreachable) { if (s is Block) @@ -2231,7 +2295,7 @@ namespace Mono.CSharp { public class SwitchLabel { Expression label; object converted; - public Location loc; + Location loc; Label il_label; bool il_label_set; @@ -2282,33 +2346,43 @@ namespace Mono.CSharp { // and then converts it to the requested type. // public bool ResolveAndReduce (EmitContext ec, Type required_type) - { - if (label == null) - return true; - + { Expression e = label.Resolve (ec); if (e == null) return false; - if (!(e is Constant)){ - Report.Error (150, loc, "A constant value is expected, got: " + e); + Constant c = e as Constant; + if (c == null){ + Report.Error (150, loc, "A constant value is expected"); return false; } - if (e is StringConstant || e is NullLiteral){ - if (required_type == TypeManager.string_type){ - converted = e; - return true; - } + if (required_type == TypeManager.string_type && e is NullLiteral) { + converted = e; + return true; } - converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc); - if (converted == null) + c = c.ToType (required_type, loc); + if (c == null) return false; + converted = c.GetValue (); return true; } + + public void Erorr_AlreadyOccurs () + { + string label; + if (converted == null) + label = "default"; + else if (converted is NullLiteral) + label = "null"; + else + label = converted.ToString (); + + Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label); + } } public class SwitchSection { @@ -2330,7 +2404,7 @@ namespace Mono.CSharp { /// /// Maps constants whose type type SwitchType to their SwitchLabels. /// - public Hashtable Elements; + public IDictionary Elements; /// /// The governing switch type @@ -2443,12 +2517,6 @@ namespace Mono.CSharp { return converted; } - static string Error152 { - get { - return "The label `{0}:' already occurs in this switch statement"; - } - } - // // Performs the basic sanity checks on the switch statement // (looks for duplicate keys and non-constant expressions). @@ -2458,141 +2526,38 @@ namespace Mono.CSharp { // bool CheckSwitch (EmitContext ec) { - Type compare_type; bool error = false; - Elements = new Hashtable (); + Elements = Sections.Count > 10 ? + (IDictionary)new Hashtable () : + (IDictionary)new ListDictionary (); - if (TypeManager.IsEnumType (SwitchType)){ - compare_type = TypeManager.EnumToUnderlying (SwitchType); - } else - compare_type = SwitchType; - foreach (SwitchSection ss in Sections){ foreach (SwitchLabel sl in ss.Labels){ - if (!sl.ResolveAndReduce (ec, SwitchType)){ - error = true; - continue; - } - if (sl.Label == null){ if (default_section != null){ - Report.Error (152, sl.loc, Error152, "default"); + sl.Erorr_AlreadyOccurs (); error = true; } default_section = ss; continue; } - - object key = sl.Converted; - - if (key is Constant) - key = ((Constant) key).GetValue (); - - if (key == null) - key = NullLiteral.Null; - - string lname = null; - if (compare_type == TypeManager.uint64_type){ - ulong v = (ulong) key; - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.int64_type){ - long v = (long) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.uint32_type){ - uint v = (uint) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.char_type){ - char v = (char) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.byte_type){ - byte v = (byte) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.sbyte_type){ - sbyte v = (sbyte) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.short_type){ - short v = (short) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.ushort_type){ - ushort v = (ushort) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.string_type){ - if (key is NullLiteral){ - if (Elements.Contains (NullLiteral.Null)) - lname = "null"; - else - Elements.Add (NullLiteral.Null, null); - } else { - string s = (string) key; - - if (Elements.Contains (s)) - lname = s; - else - Elements.Add (s, sl); - } - } else if (compare_type == TypeManager.int32_type) { - int v = (int) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } else if (compare_type == TypeManager.bool_type) { - bool v = (bool) key; - - if (Elements.Contains (v)) - lname = v.ToString (); - else - Elements.Add (v, sl); - } - else - { - throw new Exception ("Unknown switch type!" + - SwitchType + " " + compare_type); - } - - if (lname != null){ - Report.Error (152, sl.loc, Error152, "case " + lname); + if (!sl.ResolveAndReduce (ec, SwitchType)){ error = true; + continue; + } + + object key = sl.Converted; + try { + Elements.Add (key, sl); } + catch (ArgumentException) { + sl.Erorr_AlreadyOccurs (); + error = true; + } } } - if (error) - return false; - - return true; + return !error; } void EmitObjectInteger (ILGenerator ig, object k) @@ -2936,12 +2901,10 @@ namespace Mono.CSharp { if (label_count == 1) ig.Emit (OpCodes.Br, next_test); continue; - } - StringConstant str = (StringConstant) lit; ig.Emit (OpCodes.Ldloc, val); - ig.Emit (OpCodes.Ldstr, str.Value); + ig.Emit (OpCodes.Ldstr, (string)lit); if (label_count == 1) ig.Emit (OpCodes.Bne_Un, next_test); else { @@ -3124,7 +3087,7 @@ namespace Mono.CSharp { public class Lock : ExceptionStatement { Expression expr; - Statement Statement; + public Statement Statement; LocalBuilder temp; public Lock (Expression expr, Statement stmt, Location l) @@ -3395,6 +3358,10 @@ namespace Mono.CSharp { loc = l; } + public Statement Statement { + get { return statement; } + } + public override bool Resolve (EmitContext ec) { if (!ec.InUnsafe){ @@ -3827,7 +3794,7 @@ namespace Mono.CSharp { public class Using : ExceptionStatement { object expression_or_block; - Statement Statement; + public Statement Statement; ArrayList var_list; Expression expr; Type expr_type; @@ -4143,7 +4110,11 @@ namespace Mono.CSharp { statement = stmt; loc = l; } - + + public Statement Statement { + get { return statement; } + } + public override bool Resolve (EmitContext ec) { expr = expr.Resolve (ec); @@ -4355,7 +4326,7 @@ namespace Mono.CSharp { list.Add (counter [i]); } - access = new ElementAccess (copy, list, loc).Resolve (ec); + access = new ElementAccess (copy, list).Resolve (ec); if (access == null) return false; @@ -4712,7 +4683,7 @@ namespace Mono.CSharp { enumerator = new TemporaryVariable (enumerator_type, loc); enumerator.Resolve (ec); - init = new Invocation (get_enumerator, new ArrayList (), loc); + init = new Invocation (get_enumerator, new ArrayList ()); init = init.Resolve (ec); if (init == null) return false; @@ -4723,7 +4694,7 @@ namespace Mono.CSharp { MethodGroupExpr mg = new MethodGroupExpr (mi, loc); mg.InstanceExpression = enumerator; - move_next_expr = new Invocation (mg, new ArrayList (), loc); + move_next_expr = new Invocation (mg, new ArrayList ()); } get_current.InstanceExpression = enumerator;