------- 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