https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102291
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- I have tried: --- gcc/convert.c.jj 2021-01-04 10:25:38.977232194 +0100 +++ gcc/convert.c 2021-12-06 16:28:51.279775640 +0100 @@ -398,6 +398,9 @@ do_narrow (location_t loc, Exception: the LSHIFT_EXPR case above requires that we perform this operation unsigned lest we produce signed-overflow undefinedness. + Exception: for BIT_*_EXPR if type is unsigned, just + convert operands to that unsigned type, there is no + point converting to a singled type instead. And we may need to do it as unsigned if we truncate to the original size. */ if (TYPE_UNSIGNED (TREE_TYPE (expr)) @@ -424,7 +427,11 @@ do_narrow (location_t loc, > outprec)) && (ex_form == PLUS_EXPR || ex_form == MINUS_EXPR - || ex_form == MULT_EXPR))) + || ex_form == MULT_EXPR)) + || ((ex_form == BIT_AND_EXPR + || ex_form == BIT_IOR_EXPR + || ex_form == BIT_XOR_EXPR) + && TYPE_UNSIGNED (typex))) { if (!TYPE_UNSIGNED (typex)) typex = unsigned_type_for (typex); --- gcc/testsuite/gcc.dg/pr102291.c.jj 2021-12-06 16:35:36.600984273 +0100 +++ gcc/testsuite/gcc.dg/pr102291.c 2021-12-06 16:35:25.531143307 +0100 @@ -0,0 +1,33 @@ +/* PR c/102291 */ +/* { dg-do compile } */ + +extern void __assert_fail (const char *, const char *, + unsigned int, const char *) + __attribute__ ((__nothrow__ , __leaf__, __noreturn__)); +#define assert(expr) \ + ((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \ + if (expr) \ + ; /* empty */ \ + else \ + __assert_fail (#expr, __FILE__, __LINE__, \ + __ASSERT_FUNCTION); \ + })) +#define __ASSERT_FUNCTION __extension__ __PRETTY_FUNCTION__ + +#define A(c) assert (sizeof (c) == 1 || (((unsigned long) (c)) >> 8) == 0) +#define B(c) (A (c), ((unsigned char) (c))) +#define C(c) (((unsigned char) (c))) +#define D(c) ((c) | 0) +#define E(old, new) ((((unsigned long) (old)) << 6) | (((unsigned char) D (new)) & 0x3f)) + +unsigned long +foo (unsigned long x) +{ + return E (x, B (0x80)); +} + +unsigned long +bar (unsigned long x) +{ + return E (x, C (0x80)); +} but it regressed: FAIL: gcc.dg/overflow-warn-5.c (test for warnings, line 6) FAIL: gcc.dg/tree-ssa/pr94882-3.c scan-tree-dump-times optimized "_[0-9] \\^ _[0-9]" 4 FAIL: gcc.dg/tree-ssa/pr94882-3.c scan-tree-dump-times optimized "~_[0-9]+" 8 FAIL: gcc.dg/vect/vect-over-widen-3-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-3-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 9" FAIL: gcc.dg/vect/vect-over-widen-3.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-3.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 9" FAIL: gcc.dg/vect/vect-over-widen-1-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-1-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-4-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-4-big-array.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-1.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-1.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-4.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-4.c scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-1-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-1-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-4-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-4-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-1.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-1.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-4.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-4.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 8" FAIL: gcc.dg/vect/vect-over-widen-3-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-3-big-array.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 9" FAIL: gcc.dg/vect/vect-over-widen-3.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 3" FAIL: gcc.dg/vect/vect-over-widen-3.c -flto -ffat-lto-objects scan-tree-dump vect "vect_recog_over_widening_pattern: detected:[^\\n]* << 9" The overflow-warn-5.c case is just weird, there is no overflow, the function does return p & 512; where p and return type are unsigned char, just briefly looked at vect-over-widen-1.c and we vectorize one loop before and after, just the detected cases are different.