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

Reply via email to