[c#] Roslyn compiler optimizing away function call multiplication with zero
Yesterday I found this strange behavior in my C# code:
Stack<long> s = new Stack<long>(); s.Push(1); // stack contains  s.Push(2); // stack contains [1|2] s.Push(3); // stack contains [1|2|3] s.Push(s.Pop() * 0); // stack should contain [1|2|0] Console.WriteLine(string.Join("|", s.Reverse()));
I assumed the program would print
1|2|0 but in fact it printed
Looking at the generated IL code (via ILSpy) you can see that
s.Pop() * 0 is optimized to simply
// ... IL_0022: ldloc.0 IL_0023: ldc.i4.0 IL_0024: conv.i8 IL_0025: callvirt instance void class [System]System.Collections.Generic.Stack`1<int64>::Push(!0) // ...
Stack<long> s = new Stack<long>(); s.Push(1L); s.Push(2L); s.Push(3L); s.Push(0L); // <- the offending line Console.WriteLine(string.Join<long>("|", s.Reverse<long>()));
First I tested this initially under Windows 7 with Visual Studio 2015 Update 3 with both Release mode (
/optimize) and Debug mode and with various target frameworks (4.0, 4.5, 4.6 and 4.6.1). In all 8 cases the result was the same (
Then I tested it under Windows 7 with Visual Studio 2013 Update 5 (again with all the combinations of Release/Debug mode and target framework). To my surprise the statement is here not optimized away and yields the expected result
So I can conclude that this behavior is neither dependent on
/optimize nor the target framework flag but rather on the used compiler version.
Out of interest I wrote a similar code in C++ and compiled it with the current gcc version. Here a function call multiplied with zero is not optimized away and the function is properly executed.
I think such an optimization would only be valid if
stack.Pop() were a pure function (which it definitely isn't). But I'm hesitant to call this a bug, I assume it's just a feature unknown to me?
Is this "feature" anywhere documented and is there an (easy) way to disable this optimization?