diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 9a8039b9431..ebb5e65e404 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -1636,40 +1636,51 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type) || TYPE_UNSIGNED (type) == unsignedp) return type; - /* Must check the mode of the types, not the precision. Enumeral types - in C++ have precision set to match their range, but may use a wider - mode to match an ABI. If we change modes, we may wind up with bad - conversions. */ - - if (TYPE_MODE (type) == TYPE_MODE (signed_char_type_node)) + /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not + the precision; they have precision set to match their range, but + may use a wider mode to match an ABI. If we change modes, we may + wind up with bad conversions. For INTEGER_TYPEs in C, must check + the precision as well, so as to yield correct results for + bit-field types. C++ does not have these separate bit-field + types, and producing a signed or unsigned variant of an + ENUMERAL_TYPE may cause other problems as well. */ + +#define TYPE_OK(node) \ + (TYPE_MODE (type) == TYPE_MODE (node) \ + && (c_dialect_cxx () || TYPE_PRECISION (type) == TYPE_PRECISION (node))) + if (TYPE_OK (signed_char_type_node)) return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_MODE (type) == TYPE_MODE (integer_type_node)) + if (TYPE_OK (integer_type_node)) return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node)) + if (TYPE_OK (short_integer_type_node)) return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node)) + if (TYPE_OK (long_integer_type_node)) return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node)) + if (TYPE_OK (long_long_integer_type_node)) return (unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node); - if (TYPE_MODE (type) == TYPE_MODE (widest_integer_literal_type_node)) + if (TYPE_OK (widest_integer_literal_type_node)) return (unsignedp ? widest_unsigned_literal_type_node : widest_integer_literal_type_node); #if HOST_BITS_PER_WIDE_INT >= 64 - if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node)) + if (TYPE_OK (intTI_type_node)) return unsignedp ? unsigned_intTI_type_node : intTI_type_node; #endif - if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node)) + if (TYPE_OK (intDI_type_node)) return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node)) + if (TYPE_OK (intSI_type_node)) return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node)) + if (TYPE_OK (intHI_type_node)) return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node)) + if (TYPE_OK (intQI_type_node)) return unsignedp ? unsigned_intQI_type_node : intQI_type_node; +#undef TYPE_OK - return type; + if (c_dialect_cxx ()) + return type; + else + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); } /* The C version of the register_builtin_type langhook. */ |