------- Comment #3 from matz at gcc dot gnu dot org 2008-02-02 15:52 ------- Reduced by hand:
% cat x.cc enum EBorderStyle { bla = 1 }; template<typename T, typename U> inline bool compareEqual(const T& t, const U& u) { return t == u; } struct S { unsigned m_style : 4; }; void call (S *s, EBorderStyle v) { if (!compareEqual(s->m_style, v)) s->m_style = v; } The problem is confusion between the bitmap type and promotion. If you rewrite the compare into a direct expression ("if (s->m_style != v) ...") the error doesn't occur. Anyway, as written this get's generated as (004.gimple): <unnamed-unsigned:4> D.1670; unsigned char D.1673; unsigned int D.1668; D.1670 = s->m_style; D.1668 = D.1670; D.1671 = compareEqual (&D.1668, &v); retval.0 = !D.1671; Note how s->m_style gets copied first into a unsigned:4, then into an unsigned temp, which is given to compareEqual. v (the enum) stays as is. This gets further expanded into (from 130.final_cleanup): <bb 2>: if (s->m_style != v) I.e. no conversions anymore. But if we look at the expression which is tried to be expanded to RTL: do_compare_and_jump (exp=0xb7cb9438, ... (gdb) p debug_tree (exp) <ne_expr 0xb7cb9438 ... arg 0 <component_ref 0xb7cc0168 type <integer_type 0xb7d46f08 public unsigned QI size <integer_cst 0xb7cb4498 8> unit size <integer_cst 0xb7cb44b4 1> align 8 symtab 0 alias set -1 canonical type 0xb7d46f08 precision 4 min <integer_cst 0xb7d4b94c 0> max <integer_cst 0xb7d4b968 15>> arg 1 <parm_decl 0xb7cba820 v type <enumeral_type 0xb7d46888 EBorderStyle unsigned type_6 SI size <integer_cst 0xb7cb4620 constant invariant 32> unit size <integer_cst 0xb7cb440c constant invariant 4> Note how the first argument has the bitfield type (4 bit precision) and QImode, and the second argument is the enum type, which has SImode, precision 32 (but min/max being 0/1). >From there everything goes down, because the RTL expander is not prepared for compares of mismatching mode. Simply noone checks if the arguments have a different mode; it checks for VOIDmode of constants, and BLKmode, in which case it also expects a size. But if the mode is normal then it must be the same for both operands. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35056