https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84859
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Seems the kernel testcase is actually more like: void f (void*); void __attribute__ ((noinline, noclone)) g (const void *p, unsigned n) { unsigned char a[8]; if (n > sizeof a - 1) return; for (; n > 0; n -= *a) { *a = n > 255 ? 255 : n; __builtin_memcpy (a + 1, p, *a); // no warning (good) f (a); } } void __attribute__ ((noinline, noclone)) h (const void *p, unsigned n) { unsigned char a[8]; if (n > sizeof a - 1) return; for (; n > 0; n -= *a) { if (n > 255) *a = 255; else *a = n; __builtin_memcpy (a + 1, p, *a); // bogus -Warray-bounds f (a); } } where the memcpy calls don't clobber *a, but there is another call that makes a escape and could modify the value, so I'm afraid there is absolutely nothing VRP can do here and the only fix is not to warn on statements affected by jump threading. What the kernel should have used (if it couldn't use get rid of the loop altogether like it did) would be something like: void f (void*); void __attribute__ ((noinline, noclone)) g (const void *p, unsigned n) { unsigned char a[8], t; if (n > sizeof a - 1) return; for (; n > 0; n -= t) { t = n > 255 ? 255 : n; *a = t; __builtin_memcpy (a + 1, p, t); // no warning (good) f (a); } } void __attribute__ ((noinline, noclone)) h (const void *p, unsigned n) { unsigned char a[8], t; if (n > sizeof a - 1) return; for (; n > 0; n -= t) { if (n > 255) t = 255; else t = n; *a = t; __builtin_memcpy (a + 1, p, t); // no warning (good) f (a); } } i.e. introduce a temporary for the size in the current iteration and use that across the calls that might have but don't really change that.