summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-random
diff options
context:
space:
mode:
Diffstat (limited to 'mrbgems/mruby-random')
-rw-r--r--mrbgems/mruby-random/src/random.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c
index 515c0707a..10c81b946 100644
--- a/mrbgems/mruby-random/src/random.c
+++ b/mrbgems/mruby-random/src/random.c
@@ -218,6 +218,34 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
mrb_value r = mrb_nil_value();
rand_state *random;
+ /*
+ * MSC compiler bug generating invalid instructions with optimization
+ * enabled. MSC errantly uses a hardcoded value with optimizations on
+ * when using a fixed value from a union.
+ * Creating a temp volatile variable and reassigning back to the original
+ * value tricks the compiler to not perform this optimization;
+ */
+#if defined _MSC_VER && _MSC_VER >= 1923
+ /* C++ will not cast away volatile easily, so we cannot do something like
+ * volatile mrb_value rr = r; r = (mrb_value)rr; with C++.
+ * That cast does work with C.
+ * We also have to trick the compiler to not optimize away the const_cast entirely
+ * by creating and manipulating an intermediate volatile pointer.
+ */
+ volatile mrb_value *v_r;
+ volatile mrb_int ii;
+ mrb_value *p_r;
+ v_r = &r;
+ ii = 2;
+ v_r = v_r + 2;
+#if defined __cplusplus
+ p_r = const_cast<mrb_value*>(v_r - ii);
+#else
+ p_r = (mrb_value*)v_r - ii;
+#endif
+ r = *p_r;
+#endif
+
if (RARRAY_LEN(ary) > 1) {
mrb_get_args(mrb, "|o", &r);