diff --git a/src/fsharp/IlxGen.fs b/src/fsharp/IlxGen.fs index a8c0c0285cd..6cbf17f6677 100644 --- a/src/fsharp/IlxGen.fs +++ b/src/fsharp/IlxGen.fs @@ -4596,10 +4596,18 @@ and GenDefaultValue cenv cgbuf eenv (ty, m) = // Ensure that we have an g.CompilerGlobalState assert(g.CompilerGlobalState |> Option.isSome) AllocLocal cenv cgbuf eenv true (g.CompilerGlobalState.Value.IlxGenNiceNameGenerator.FreshCompilerGeneratedName ("default", m), ilTy, false) scopeMarks + // We can normally rely on .NET IL zero-initialization of the temporaries + // we create to get zero values for struct types. + // + // However this doesn't work when + // - we're reusing a local (realloc) + // - SkipLocalsInit is active (not eenv.initLocals) + // - we're in a loop (when we may get a backward branch, and the local may have been realloc'd elsewhere) + // // "initobj" (Generated by EmitInitLocal) doesn't work on byref types // But ilzero(&ty) only gets generated in the built-in get-address function so // we can just rely on zeroinit of all IL locals. - if (realloc || not eenv.initLocals) && not (IsILTypeByref ilTy) then + if (realloc || not eenv.initLocals || eenv.isInLoop) && not (IsILTypeByref ilTy) then EmitInitLocal cgbuf ilTy locIdx EmitGetLocal cgbuf ilTy locIdx @@ -6083,7 +6091,11 @@ and GenLetRecFixup cenv cgbuf eenv (ilxCloSpec: IlxClosureSpec, e, ilField: ILFi /// Generate letrec bindings and GenLetRecBindings cenv (cgbuf: CodeGenBuffer) eenv (allBinds: Bindings, m) = + + // 'let rec' bindings are always considered to be in loops, that is each may have backward branches for the + // tailcalls back to the entry point. This means we don't rely on zero-init of mutable locals let eenv = SetIsInLoop true eenv + // Fix up recursion for non-toplevel recursive bindings let bindsPossiblyRequiringFixup = allBinds |> List.filter (fun b -> diff --git a/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs b/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs index b956480ef58..db432c5c982 100644 --- a/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs +++ b/tests/fsharp/Compiler/CodeGen/EmittedIL/TaskGeneratedCode.fs @@ -1161,165 +1161,167 @@ type Generic1InGeneric1<'T>() = """ """ - .method public strict virtual instance void - MoveNext() cil managed - { - .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext - - .maxstack 5 - .locals init (int32 V_0, - class [runtime]System.Exception V_1, - bool V_2, - class [runtime]System.Threading.Tasks.Task`1 V_3, - bool V_4, - bool V_5, - !A V_6, - !A V_7, - valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 V_8, - class [runtime]System.Exception V_9, - class [runtime]System.Exception V_10) - IL_0000: ldarg.0 - IL_0001: ldfld int32 valuetype Test/clo@7::ResumptionPoint - IL_0006: stloc.0 - IL_0007: ldloc.0 - IL_0008: ldc.i4.1 - IL_0009: sub - IL_000a: switch ( - IL_0015) - IL_0013: br.s IL_0018 - - IL_0015: nop - IL_0016: br.s IL_001b - - IL_0018: nop - IL_0019: ldnull - IL_001a: stloc.1 - .try - { - IL_001b: ldloc.0 - IL_001c: ldc.i4.1 - IL_001d: sub - IL_001e: switch ( - IL_0029) - IL_0027: br.s IL_002c - - IL_0029: nop - IL_002a: br.s IL_0055 - - IL_002c: nop - IL_002d: ldarg.0 - IL_002e: ldfld class [runtime]System.Threading.Tasks.Task`1 valuetype Test/clo@7::computation - IL_0033: stloc.3 - IL_0034: ldarg.0 - IL_0035: ldloc.3 - IL_0036: callvirt instance valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1 class [netstandard]System.Threading.Tasks.Task`1::GetAwaiter() - IL_003b: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter - IL_0040: ldc.i4.1 - IL_0041: stloc.s V_4 - IL_0043: ldarg.0 - IL_0044: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter - IL_0049: call instance bool valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted() - IL_004e: brfalse.s IL_0052 - - IL_0050: br.s IL_006b - - IL_0052: ldc.i4.0 - IL_0053: brfalse.s IL_0059 - - IL_0055: ldc.i4.1 - IL_0056: nop - IL_0057: br.s IL_0062 - - IL_0059: ldarg.0 - IL_005a: ldc.i4.1 - IL_005b: stfld int32 valuetype Test/clo@7::ResumptionPoint - IL_0060: ldc.i4.0 - IL_0061: nop - IL_0062: stloc.s V_5 - IL_0064: ldloc.s V_5 - IL_0066: stloc.s V_4 - IL_0068: nop - IL_0069: br.s IL_006c - - IL_006b: nop - IL_006c: ldloc.s V_4 - IL_006e: brfalse.s IL_0092 - - IL_0070: ldarg.0 - IL_0071: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter - IL_0076: call instance !0 valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult() - IL_007b: stloc.s V_6 - IL_007d: ldloc.s V_6 - IL_007f: stloc.s V_7 - IL_0081: ldarg.0 - IL_0082: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data - IL_0087: ldloc.s V_7 - IL_0089: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result - IL_008e: ldc.i4.1 - IL_008f: nop - IL_0090: br.s IL_00ab - - IL_0092: ldarg.0 - IL_0093: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data - IL_0098: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder - IL_009d: ldarg.0 - IL_009e: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter - IL_00a3: ldarg.0 - IL_00a4: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompleted,valuetype Test/clo@7>(!!0&, - !!1&) - IL_00a9: ldc.i4.0 - IL_00aa: nop - IL_00ab: brfalse.s IL_00b9 - - IL_00ad: ldarg.0 - IL_00ae: ldloc.s V_8 - IL_00b0: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter - IL_00b5: ldc.i4.1 - IL_00b6: nop - IL_00b7: br.s IL_00bb - - IL_00b9: ldc.i4.0 - IL_00ba: nop - IL_00bb: stloc.2 - IL_00bc: ldloc.2 - IL_00bd: brfalse.s IL_00dc - - IL_00bf: ldarg.0 - IL_00c0: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data - IL_00c5: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder - IL_00ca: ldarg.0 - IL_00cb: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data - IL_00d0: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result - IL_00d5: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) - IL_00da: leave.s IL_00ea - - IL_00dc: leave.s IL_00ea - - } - catch [runtime]System.Object - { - IL_00de: castclass [runtime]System.Exception - IL_00e3: stloc.s V_9 - IL_00e5: ldloc.s V_9 - IL_00e7: stloc.1 - IL_00e8: leave.s IL_00ea - - } - IL_00ea: ldloc.1 - IL_00eb: stloc.s V_10 - IL_00ed: ldloc.s V_10 - IL_00ef: brtrue.s IL_00f2 - - IL_00f1: ret - - IL_00f2: ldarg.0 - IL_00f3: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data - IL_00f8: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder - IL_00fd: ldloc.s V_10 - IL_00ff: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) - IL_0104: ret - } - +.method public strict virtual instance void + MoveNext() cil managed + { + .override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext + + .maxstack 5 + .locals init (int32 V_0, + class [runtime]System.Exception V_1, + bool V_2, + class [runtime]System.Threading.Tasks.Task`1 V_3, + bool V_4, + bool V_5, + !A V_6, + !A V_7, + valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 V_8, + class [runtime]System.Exception V_9, + class [runtime]System.Exception V_10) + IL_0000: ldarg.0 + IL_0001: ldfld int32 valuetype Test/clo@7::ResumptionPoint + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: ldc.i4.1 + IL_0009: sub + IL_000a: switch ( + IL_0015) + IL_0013: br.s IL_0018 + + IL_0015: nop + IL_0016: br.s IL_001b + + IL_0018: nop + IL_0019: ldnull + IL_001a: stloc.1 + .try + { + IL_001b: ldloc.0 + IL_001c: ldc.i4.1 + IL_001d: sub + IL_001e: switch ( + IL_0029) + IL_0027: br.s IL_002c + + IL_0029: nop + IL_002a: br.s IL_0055 + + IL_002c: nop + IL_002d: ldarg.0 + IL_002e: ldfld class [runtime]System.Threading.Tasks.Task`1 valuetype Test/clo@7::computation + IL_0033: stloc.3 + IL_0034: ldarg.0 + IL_0035: ldloc.3 + IL_0036: callvirt instance valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1 class [netstandard]System.Threading.Tasks.Task`1::GetAwaiter() + IL_003b: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter + IL_0040: ldc.i4.1 + IL_0041: stloc.s V_4 + IL_0043: ldarg.0 + IL_0044: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter + IL_0049: call instance bool valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted() + IL_004e: brfalse.s IL_0052 + + IL_0050: br.s IL_006b + + IL_0052: ldc.i4.0 + IL_0053: brfalse.s IL_0059 + + IL_0055: ldc.i4.1 + IL_0056: nop + IL_0057: br.s IL_0062 + + IL_0059: ldarg.0 + IL_005a: ldc.i4.1 + IL_005b: stfld int32 valuetype Test/clo@7::ResumptionPoint + IL_0060: ldc.i4.0 + IL_0061: nop + IL_0062: stloc.s V_5 + IL_0064: ldloc.s V_5 + IL_0066: stloc.s V_4 + IL_0068: nop + IL_0069: br.s IL_006c + + IL_006b: nop + IL_006c: ldloc.s V_4 + IL_006e: brfalse.s IL_0092 + + IL_0070: ldarg.0 + IL_0071: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter + IL_0076: call instance !0 valuetype [netstandard]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult() + IL_007b: stloc.s V_6 + IL_007d: ldloc.s V_6 + IL_007f: stloc.s V_7 + IL_0081: ldarg.0 + IL_0082: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data + IL_0087: ldloc.s V_7 + IL_0089: stfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_008e: ldc.i4.1 + IL_008f: nop + IL_0090: br.s IL_00ab + + IL_0092: ldarg.0 + IL_0093: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data + IL_0098: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_009d: ldarg.0 + IL_009e: ldflda valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter + IL_00a3: ldarg.0 + IL_00a4: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::AwaitUnsafeOnCompleted,valuetype Test/clo@7>(!!0&, + !!1&) + IL_00a9: ldc.i4.0 + IL_00aa: nop + IL_00ab: brfalse.s IL_00c1 + + IL_00ad: ldarg.0 + IL_00ae: ldloca.s V_8 + IL_00b0: initobj valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 + IL_00b6: ldloc.s V_8 + IL_00b8: stfld valuetype [runtime]System.Runtime.CompilerServices.TaskAwaiter`1 valuetype Test/clo@7::awaiter + IL_00bd: ldc.i4.1 + IL_00be: nop + IL_00bf: br.s IL_00c3 + + IL_00c1: ldc.i4.0 + IL_00c2: nop + IL_00c3: stloc.2 + IL_00c4: ldloc.2 + IL_00c5: brfalse.s IL_00e4 + + IL_00c7: ldarg.0 + IL_00c8: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data + IL_00cd: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_00d2: ldarg.0 + IL_00d3: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data + IL_00d8: ldfld !0 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::Result + IL_00dd: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetResult(!0) + IL_00e2: leave.s IL_00f2 + + IL_00e4: leave.s IL_00f2 + + } + catch [runtime]System.Object + { + IL_00e6: castclass [runtime]System.Exception + IL_00eb: stloc.s V_9 + IL_00ed: ldloc.s V_9 + IL_00ef: stloc.1 + IL_00f0: leave.s IL_00f2 + + } + IL_00f2: ldloc.1 + IL_00f3: stloc.s V_10 + IL_00f5: ldloc.s V_10 + IL_00f7: brtrue.s IL_00fa + + IL_00f9: ret + + IL_00fa: ldarg.0 + IL_00fb: ldflda valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1 valuetype Test/clo@7::Data + IL_0100: ldflda valuetype [runtime]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1 valuetype [FSharp.Core]Microsoft.FSharp.Control.TaskStateMachineData`1::MethodBuilder + IL_0105: ldloc.s V_10 + IL_0107: call instance void valuetype [netstandard]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1::SetException(class [netstandard]System.Exception) + IL_010c: ret + } + """ ]) #endif diff --git a/tests/fsharp/core/forexpression/test.fsx b/tests/fsharp/core/forexpression/test.fsx index 0fada85b01b..f745d926380 100644 --- a/tests/fsharp/core/forexpression/test.fsx +++ b/tests/fsharp/core/forexpression/test.fsx @@ -131,6 +131,38 @@ do test "ilistSum" (expectedArraySum = ilistSum ) do test "rangeSum" (expectedRangeSum = rangeSum ) do test "stringSum" (expectedStringSum = stringSum ) +module RegressionCase = + [] + type ColorF = + val r: float32 + val g: float32 + val b: float32 + + new (r, g, b) = { + ColorF.r = r + ColorF.g = g + ColorF.b = b + } + + static member (+) (first: ColorF, second: ColorF) = + ColorF(first.r + second.r, first.g + second.g, first.b + second.b) + + let Issue12333 () = + for x = 0 to 1 do + printfn "iter %d" x + let mutable color: ColorF = ColorF() + printfn "init color %g %g %g" color.r color.g color.b + test "lclwejcjwl1" (color.r = 0.0f) + test "lclwejcjwl2" (color.g = 0.0f) + test "lclwejcjwl3" (color.b = 0.0f) + for s = 0 to 1 do + let temp = ColorF(0.1f, 0.1f, 0.1f) + color <- color + temp + printfn "color %g %g %g" color.r color.g color.b + + + Issue12333() // should run without exception + #if TESTS_AS_APP let RUN() = !failures #else diff --git a/tests/fsharp/core/forexpression/version46/test.fs b/tests/fsharp/core/forexpression/version46/test.fs deleted file mode 100644 index c2042a9f0c1..00000000000 --- a/tests/fsharp/core/forexpression/version46/test.fs +++ /dev/null @@ -1,41 +0,0 @@ -//An integer for loop must use a simple identifier -module Global - -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -// usingWildcard counts using a wildcard in a for loop -let usingWildcard () = - let mutable sum = 0 - for _ = 0 to count do - sum <- sum + 1 - - printfn "usingWildcards expected to produce sum of 4 : sum='%d'"sum - -do test "wildCard" (4 = usingWildcard () ) - -#if TESTS_AS_APP -let RUN() = !failures -#else -let aa = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 -#endif - diff --git a/tests/fsharp/core/forexpression/version47/test.fs b/tests/fsharp/core/forexpression/version47/test.fs deleted file mode 100644 index 868a4757ce2..00000000000 --- a/tests/fsharp/core/forexpression/version47/test.fs +++ /dev/null @@ -1,43 +0,0 @@ -//usingWildcards expected to produce sum of 4 : sum='4' -#if TESTS_AS_APP -module Core_forexpression_47 -#endif - -let failures = ref [] - -let report_failure (s : string) = - stderr.Write" NO: " - stderr.WriteLine s - failures := !failures @ [s] - -let test (s : string) b = - stderr.Write(s) - if b then stderr.WriteLine " OK" - else report_failure (s) - -let check s b1 b2 = test s (b1 = b2) - -// usingWildcard counts using a wildcard in a for loop -let usingWildcard () = - let mutable sum = 0 - for _ = 0 to count do - sum <- sum + 1 - - printfn "usingWildcards expected to produce sum of 4 : sum='%d'"sum - -do test "wildCard" (4 = usingWildcard () ) - -#if TESTS_AS_APP -let RUN() = !failures -#else -let aa = - match !failures with - | [] -> - stdout.WriteLine "Test Passed" - System.IO.File.WriteAllText("test.ok","ok") - exit 0 - | _ -> - stdout.WriteLine "Test Failed" - exit 1 -#endif - diff --git a/tests/fsharp/tests.fs b/tests/fsharp/tests.fs index 708a3ebcdd9..f05180bde9a 100644 --- a/tests/fsharp/tests.fs +++ b/tests/fsharp/tests.fs @@ -325,6 +325,15 @@ module CoreTests = [] let ``nbody-FSI_BASIC`` () = singleTestBuildAndRun "perf/nbody" FSI_BASIC + [] + let ``forexpression-FSC_BASIC_OPT_MINUS`` () = singleTestBuildAndRun "core/forexpression" FSC_BASIC_OPT_MINUS + + [] + let ``forexpression-FSC_BASIC`` () = singleTestBuildAndRun "core/forexpression" FSC_BASIC + + [] + let ``forexpression-FSI_BASIC`` () = singleTestBuildAndRun "core/forexpression" FSI_BASIC + [] let ``letrec (mutrec variations part two) FSC_BASIC_OPT_MINUS`` () = singleTestBuildAndRun "core/letrec-mutrec2" FSC_BASIC_OPT_MINUS