public override bool Resolve (BlockContext bc)
{
ctch.Filter = ctch.Filter.Resolve (bc);
- var c = ctch.Filter as Constant;
- if (c != null && !c.IsDefaultValue) {
- bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
+
+ if (ctch.Filter != null) {
+ if (ctch.Filter.ContainsEmitWithAwait ()) {
+ bc.Report.Error (7094, ctch.Filter.Location, "The `await' operator cannot be used in the filter expression of a catch clause");
+ }
+
+ var c = ctch.Filter as Constant;
+ if (c != null && !c.IsDefaultValue) {
+ bc.Report.Warning (7095, 1, ctch.Filter.Location, "Exception filter expression is a constant");
+ }
}
return true;
}
}
- Block.Emit (ec);
+ if (!Block.HasAwait)
+ Block.Emit (ec);
}
void EmitCatchVariableStore (EmitContext ec)
}
}
- public override bool Resolve (BlockContext ec)
+ public override bool Resolve (BlockContext bc)
{
- using (ec.Set (ResolveContext.Options.CatchScope)) {
+ using (bc.Set (ResolveContext.Options.CatchScope)) {
if (type_expr != null) {
- type = type_expr.ResolveAsType (ec);
+ type = type_expr.ResolveAsType (bc);
if (type == null)
return false;
- if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, ec.BuiltinTypes.Exception, false)) {
- ec.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
+ if (type.BuiltinType != BuiltinTypeSpec.Type.Exception && !TypeSpec.IsBaseClass (type, bc.BuiltinTypes.Exception, false)) {
+ bc.Report.Error (155, loc, "The type caught or thrown must be derived from System.Exception");
} else if (li != null) {
li.Type = type;
- li.PrepareAssignmentAnalysis (ec);
+ li.PrepareAssignmentAnalysis (bc);
// source variable is at the top of the stack
Expression source = new EmptyExpression (li.Type);
}
Block.SetCatchBlock ();
- return Block.Resolve (ec);
+ return Block.Resolve (bc);
}
}
public Block Block;
List<Catch> clauses;
readonly bool inside_try_finally;
+ List<Catch> catch_sm;
public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
: base (l)
ok &= c.Resolve (bc);
+ if (c.Block.HasAwait) {
+ if (catch_sm == null)
+ catch_sm = new List<Catch> ();
+
+ catch_sm.Add (c);
+ }
+
if (c.Filter != null)
continue;
Block.Emit (ec);
- foreach (Catch c in clauses)
+ LocalBuilder state_variable = null;
+ foreach (Catch c in clauses) {
c.Emit (ec);
+ if (catch_sm != null) {
+ if (state_variable == null)
+ state_variable = ec.GetTemporaryLocal (ec.Module.Compiler.BuiltinTypes.Int);
+
+ var index = catch_sm.IndexOf (c);
+ if (index < 0)
+ continue;
+
+ ec.EmitInt (index + 1);
+ ec.Emit (OpCodes.Stloc, state_variable);
+ }
+ }
+
if (!inside_try_finally)
ec.EndExceptionBlock ();
+
+ if (state_variable != null) {
+ ec.Emit (OpCodes.Ldloc, state_variable);
+
+ var labels = new Label [catch_sm.Count + 1];
+ for (int i = 0; i < labels.Length; ++i) {
+ labels [i] = ec.DefineLabel ();
+ }
+
+ var end = ec.DefineLabel ();
+ ec.Emit (OpCodes.Switch, labels);
+
+ // 0 value is default label
+ ec.MarkLabel (labels [0]);
+
+ for (int i = 0; i < catch_sm.Count; ++i) {
+ ec.Emit (OpCodes.Br, end);
+
+ ec.MarkLabel (labels [i + 1]);
+ catch_sm [i].Block.Emit (ec);
+ }
+
+ ec.MarkLabel (end);
+ }
}
protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
--- /dev/null
+using System;
+using System.Threading.Tasks;
+
+class C
+{
+ static int counter;
+ public static async Task TestSingleAwait (bool throwException)
+ {
+ try {
+ if (throwException)
+ throw new ApplicationException ();
+ } catch (ApplicationException ex) {
+ Console.WriteLine ("x1a");
+ ++counter;
+ await Call ();
+ Console.WriteLine ("x2a");
+ ++counter;
+ } catch {
+ throw;
+ }
+
+ Console.WriteLine ("end");
+ }
+
+ public static async Task TestDoubleAwait (bool throwException)
+ {
+ try {
+ if (throwException)
+ throw new ApplicationException ();
+ } catch (ApplicationException ex) {
+ Console.WriteLine ("x1a");
+ ++counter;
+ await Call ();
+ Console.WriteLine ("x2a");
+ ++counter;
+ } catch {
+ Console.WriteLine ("x1b");
+ counter += 4;
+ await Call ();
+ Console.WriteLine ("x2b");
+ counter += 7;
+ }
+
+ Console.WriteLine ("end");
+ }
+
+ static Task Call ()
+ {
+ return Task.Factory.StartNew (() => false);
+ }
+
+ void HH ()
+ {
+ try {
+ throw new ApplicationException ();
+ } catch {
+ throw;
+ }
+ }
+
+ public static int Main ()
+ {
+ TestSingleAwait (true).Wait ();
+ Console.WriteLine (counter);
+ if (counter != 2)
+ return 1;
+
+ TestSingleAwait (false).Wait ();
+ if (counter != 2)
+ return 1;
+
+ counter = 0;
+
+ TestDoubleAwait (true).Wait ();
+ Console.WriteLine (counter);
+ if (counter != 2)
+ return 3;
+
+ TestDoubleAwait (false).Wait ();
+ if (counter != 2)
+ return 4;
+
+ return 0;
+ }
+}
</method>\r
</type>\r
</test>\r
+ <test name="test-async-63.cs">\r
+ <type name="C">\r
+ <method name="System.Threading.Tasks.Task TestSingleAwait(Boolean)" attrs="150">\r
+ <size>41</size>\r
+ </method>\r
+ <method name="System.Threading.Tasks.Task TestDoubleAwait(Boolean)" attrs="150">\r
+ <size>41</size>\r
+ </method>\r
+ <method name="System.Threading.Tasks.Task Call()" attrs="145">\r
+ <size>48</size>\r
+ </method>\r
+ <method name="Void HH()" attrs="129">\r
+ <size>12</size>\r
+ </method>\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>152</size>\r
+ </method>\r
+ <method name="Boolean <Call>m__0()" attrs="145">\r
+ <size>9</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ <type name="C+<TestSingleAwait>c__async0">\r
+ <method name="Void MoveNext()" attrs="486">\r
+ <size>274</size>\r
+ </method>\r
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">\r
+ <size>13</size>\r
+ </method>\r
+ </type>\r
+ <type name="C+<TestDoubleAwait>c__async1">\r
+ <method name="Void MoveNext()" attrs="486">\r
+ <size>410</size>\r
+ </method>\r
+ <method name="Void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine)" attrs="486">\r
+ <size>13</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
<test name="test-cls-00.cs">\r
<type name="CLSCLass_6">\r
<method name="Void add_Disposed(Delegate)" attrs="2182">\r