-#define MEM_WRAP_CHECK(n,t) \
- (void)(UNLIKELY(sizeof(t) > 1 && ((MEM_SIZE)(n)+0.0) > MEM_SIZE_MAX/sizeof(t)) && (croak_memory_wrap(),0))
-#define MEM_WRAP_CHECK_1(n,t,a) \
- (void)(UNLIKELY(sizeof(t) > 1 && ((MEM_SIZE)(n)+0.0) > MEM_SIZE_MAX/sizeof(t)) && (Perl_croak_nocontext("%s",(a)),0))
+
+/* This expression will be constant-folded at compile time. It checks
+ * whether or not the type of the count n is so small (e.g. U8 or U16, or
+ * U32 on 64-bit systems) that there's no way a wrap-around could occur.
+ * As well as avoiding the need for a run-time check in some cases, it's
+ * designed to avoid compiler warnings like:
+ * comparison is always false due to limited range of data type
+ */
+
+# define _MEM_WRAP_NEEDS_RUNTIME_CHECK(n,t) \
+ (sizeof(t) > ((MEM_SIZE)1 << 8*(sizeof(MEM_SIZE) - sizeof(n))))
+
+/* This is written in a slightly odd way to avoid various spurious
+ * compiler warnings. We *want* to write the expression as
+ * _MEM_WRAP_NEEDS_RUNTIME_CHECK(n,t) && (n > C)
+ * (for some compile-time constant C), but even when the LHS
+ * constant-folds to false at compile-time, g++ insists on emitting
+ * warnings about the RHS (e.g. "comparison is always false"), so instead
+ * we write it as
+ *
+ * (cond ? n : X) > C
+ *
+ * where X is a constant with X > C always false. Choosing a value for X
+ * is tricky. If 0, some compilers will complain about 0 > C always being
+ * false; if 1, Coverity complains when n happens to be the constant value
+ * '1', that cond ? 1 : 1 has the same value on both branches; so use C
+ * for X and hope that nothing else whines.
+ */
+
+# define _MEM_WRAP_WILL_WRAP(n,t) \
+ ((_MEM_WRAP_NEEDS_RUNTIME_CHECK(n,t) ? (MEM_SIZE)(n) : \
+ MEM_SIZE_MAX/sizeof(t)) > MEM_SIZE_MAX/sizeof(t))
+
+# define MEM_WRAP_CHECK(n,t) \
+ (void)(UNLIKELY(_MEM_WRAP_WILL_WRAP(n,t)) \
+ && (croak_memory_wrap(),0))
+
+# define MEM_WRAP_CHECK_1(n,t,a) \
+ (void)(UNLIKELY(_MEM_WRAP_WILL_WRAP(n,t)) \
+ && (Perl_croak_nocontext("%s",(a)),0))
+