From 93ae706d6eaef7a1d1881bac4a3aaf5c8710f67a Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 27 Sep 2017 23:17:46 -0700 Subject: [PATCH] Make readonlyness of ref-ternary the AND of operands (#22384) Fixes #22378 --- .../CSharp/Portable/CodeGen/EmitAddress.cs | 2 +- .../CodeGenConditionalOperatorTests.cs | 180 ++++++++++++++++++ .../CodeGenRefConditionalOperatorTests.cs | 6 +- 3 files changed, 184 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs index d591bc14ae6..b4059bd1fb5 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs @@ -415,7 +415,7 @@ private bool HasHome(BoundExpression expression, bool needWriteable) // branch that has no home will need a temporary // if both have no home, just say whole expression has no home // so we could just use one temp for the whole thing - return HasHome(ternary.Consequence, needWriteable) || HasHome(ternary.Alternative, needWriteable); + return HasHome(ternary.Consequence, needWriteable) && HasHome(ternary.Alternative, needWriteable); default: return false; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs index 4cdd403c650..5ae1d21e657 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenConditionalOperatorTests.cs @@ -2471,6 +2471,186 @@ static void Main() CompileAndVerify(source, expectedOutput: expectedOutput); } + [Fact] + public void RefReadonlyConditional() + { + var comp = CompileAndVerify(@" +using System; + +struct S +{ + public int X; + public S(int x) => X = x; + + public void Mutate() => X++; +} + +class C +{ + static void Main() + { + S local1 = new S(0); + S local2 = new S(0); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + bool condition = false; + + (condition ? ref local1 : ref local2).Mutate(); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + (condition ? ref local1 : ref local2).X = 0; + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + ref readonly S ro1 = ref local1; + ref readonly S ro2 = ref local2; + + (condition ? ref local1 : ref ro2).Mutate(); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + (condition ? ref ro1 : ref local2).Mutate(); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + (!condition ? ref local1 : ref ro2).Mutate(); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + + (!condition ? ref ro1 : ref local2).Mutate(); + Console.WriteLine(local1.X); + Console.WriteLine(local2.X); + } +}", expectedOutput: @"0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0"); + comp.VerifyIL("C.Main", @" +{ + // Code size 290 (0x122) + .maxstack 3 + .locals init (S V_0, //local1 + S V_1, //local2 + S& V_2, //ro1 + S& V_3, //ro2 + S V_4) + IL_0000: ldloca.s V_0 + IL_0002: ldc.i4.0 + IL_0003: call ""S..ctor(int)"" + IL_0008: ldloca.s V_1 + IL_000a: ldc.i4.0 + IL_000b: call ""S..ctor(int)"" + IL_0010: ldloc.0 + IL_0011: ldfld ""int S.X"" + IL_0016: call ""void System.Console.WriteLine(int)"" + IL_001b: ldloc.1 + IL_001c: ldfld ""int S.X"" + IL_0021: call ""void System.Console.WriteLine(int)"" + IL_0026: ldc.i4.0 + IL_0027: dup + IL_0028: brtrue.s IL_002e + IL_002a: ldloca.s V_1 + IL_002c: br.s IL_0030 + IL_002e: ldloca.s V_0 + IL_0030: call ""void S.Mutate()"" + IL_0035: ldloc.0 + IL_0036: ldfld ""int S.X"" + IL_003b: call ""void System.Console.WriteLine(int)"" + IL_0040: ldloc.1 + IL_0041: ldfld ""int S.X"" + IL_0046: call ""void System.Console.WriteLine(int)"" + IL_004b: dup + IL_004c: brtrue.s IL_0052 + IL_004e: ldloca.s V_1 + IL_0050: br.s IL_0054 + IL_0052: ldloca.s V_0 + IL_0054: ldc.i4.0 + IL_0055: stfld ""int S.X"" + IL_005a: ldloc.0 + IL_005b: ldfld ""int S.X"" + IL_0060: call ""void System.Console.WriteLine(int)"" + IL_0065: ldloc.1 + IL_0066: ldfld ""int S.X"" + IL_006b: call ""void System.Console.WriteLine(int)"" + IL_0070: ldloca.s V_0 + IL_0072: stloc.2 + IL_0073: ldloca.s V_1 + IL_0075: stloc.3 + IL_0076: dup + IL_0077: brtrue.s IL_0081 + IL_0079: ldloc.3 + IL_007a: ldobj ""S"" + IL_007f: br.s IL_0082 + IL_0081: ldloc.0 + IL_0082: stloc.s V_4 + IL_0084: ldloca.s V_4 + IL_0086: call ""void S.Mutate()"" + IL_008b: ldloc.0 + IL_008c: ldfld ""int S.X"" + IL_0091: call ""void System.Console.WriteLine(int)"" + IL_0096: ldloc.1 + IL_0097: ldfld ""int S.X"" + IL_009c: call ""void System.Console.WriteLine(int)"" + IL_00a1: dup + IL_00a2: brtrue.s IL_00a7 + IL_00a4: ldloc.1 + IL_00a5: br.s IL_00ad + IL_00a7: ldloc.2 + IL_00a8: ldobj ""S"" + IL_00ad: stloc.s V_4 + IL_00af: ldloca.s V_4 + IL_00b1: call ""void S.Mutate()"" + IL_00b6: ldloc.0 + IL_00b7: ldfld ""int S.X"" + IL_00bc: call ""void System.Console.WriteLine(int)"" + IL_00c1: ldloc.1 + IL_00c2: ldfld ""int S.X"" + IL_00c7: call ""void System.Console.WriteLine(int)"" + IL_00cc: dup + IL_00cd: brfalse.s IL_00d7 + IL_00cf: ldloc.3 + IL_00d0: ldobj ""S"" + IL_00d5: br.s IL_00d8 + IL_00d7: ldloc.0 + IL_00d8: stloc.s V_4 + IL_00da: ldloca.s V_4 + IL_00dc: call ""void S.Mutate()"" + IL_00e1: ldloc.0 + IL_00e2: ldfld ""int S.X"" + IL_00e7: call ""void System.Console.WriteLine(int)"" + IL_00ec: ldloc.1 + IL_00ed: ldfld ""int S.X"" + IL_00f2: call ""void System.Console.WriteLine(int)"" + IL_00f7: brfalse.s IL_00fc + IL_00f9: ldloc.1 + IL_00fa: br.s IL_0102 + IL_00fc: ldloc.2 + IL_00fd: ldobj ""S"" + IL_0102: stloc.s V_4 + IL_0104: ldloca.s V_4 + IL_0106: call ""void S.Mutate()"" + IL_010b: ldloc.0 + IL_010c: ldfld ""int S.X"" + IL_0111: call ""void System.Console.WriteLine(int)"" + IL_0116: ldloc.1 + IL_0117: ldfld ""int S.X"" + IL_011c: call ""void System.Console.WriteLine(int)"" + IL_0121: ret +}"); + } + [Fact] public void RefConditionalOperatorInValConditional() { diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs index aad20e5c6d6..0576ae09a47 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenRefConditionalOperatorTests.cs @@ -1113,7 +1113,7 @@ public override string ToString() } "; - var comp = CompileAndVerify(source, additionalRefs: new[] { SystemRuntimeFacadeRef, ValueTupleRef }, expectedOutput: "042", verify: false); + var comp = CompileAndVerify(source, additionalRefs: new[] { SystemRuntimeFacadeRef, ValueTupleRef }, expectedOutput: "00", verify: false); comp.VerifyDiagnostics(); comp.VerifyIL("Program.Test", @" @@ -1124,8 +1124,8 @@ .locals init (S1 V_0) IL_0000: ldarg.0 IL_0001: brtrue.s IL_000b IL_0003: ldarg.1 - IL_0004: ldflda ""S1 C1.field1"" - IL_0009: br.s IL_0014 + IL_0004: ldfld ""S1 C1.field1"" + IL_0009: br.s IL_0011 IL_000b: ldarg.1 IL_000c: ldfld ""S1 C1.field"" IL_0011: stloc.0 -- GitLab