Hi! If an enum has mode attribute, then finish_enum uses the precision from its mode (and complains if the enumerators don't fit into that precision), but will use TYPE_{MIN,MAX}_VALUE from int's precision instead.
Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-02-04 Jakub Jelinek <ja...@redhat.com> PR c/69669 * c-decl.c (finish_enum): When honoring mode attribute, make sure to use proper TYPE_MIN_VALUE and TYPE_MAX_VALUE. * c-c++-common/pr69669.c: New test. --- gcc/c/c-decl.c.jj 2016-01-29 21:36:15.000000000 +0100 +++ gcc/c/c-decl.c 2016-02-04 16:58:03.461160993 +0100 @@ -8037,7 +8037,24 @@ finish_enum (tree enumtype, tree values, precision = MAX (tree_int_cst_min_precision (minnode, sign), tree_int_cst_min_precision (maxnode, sign)); - if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node)) + /* If the precision of the type was specified with an attribute and it + was too small, give an error. Otherwise, use it. */ + if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) + { + if (precision > TYPE_PRECISION (enumtype)) + { + TYPE_PRECISION (enumtype) = 0; + error ("specified mode too small for enumeral values"); + } + else + precision = TYPE_PRECISION (enumtype); + } + else + TYPE_PRECISION (enumtype) = 0; + + if (TYPE_PACKED (enumtype) + || precision > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (enumtype)) { tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); if (tem == NULL) @@ -8054,17 +8071,7 @@ finish_enum (tree enumtype, tree values, TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); TYPE_ALIGN (enumtype) = TYPE_ALIGN (tem); TYPE_SIZE (enumtype) = 0; - - /* If the precision of the type was specified with an attribute and it - was too small, give an error. Otherwise, use it. */ - if (TYPE_PRECISION (enumtype) - && lookup_attribute ("mode", attributes)) - { - if (precision > TYPE_PRECISION (enumtype)) - error ("specified mode too small for enumeral values"); - } - else - TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); layout_type (enumtype); --- gcc/testsuite/c-c++-common/pr69669.c.jj 2016-02-04 17:08:59.475060778 +0100 +++ gcc/testsuite/c-c++-common/pr69669.c 2016-02-04 17:08:15.000000000 +0100 @@ -0,0 +1,10 @@ +/* PR c/69669 */ +/* { dg-do compile } */ + +enum __attribute__((mode(QI))) E { F = 1 }; + +void +foo (enum E *x, int y) +{ + *x = (enum E) y; +} Jakub