* c-common.c (c_common_signed_or_unsigned_type): Examine mode,
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Sep 2003 06:04:14 +0000 (06:04 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 23 Sep 2003 06:04:14 +0000 (06:04 +0000)
        not precision.
* g++.dg/opt/enum1.C: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@71677 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-common.c
gcc/testsuite/g++.dg/opt/enum1.C [new file with mode: 0644]

index a7b8b49..2dd2543 100644 (file)
@@ -1,3 +1,8 @@
+2003-09-22  Richard Henderson  <rth@redhat.com>
+
+       * c-common.c (c_common_signed_or_unsigned_type): Examine mode, 
+       not precision.
+
 2003-09-22  David Edelsohn  <edelsohn@gnu.org>
            Hartmut Penner  <hpenner@de.ibm.com>
 
index 39c6a57..905ad93 100644 (file)
@@ -1982,32 +1982,37 @@ c_common_signed_or_unsigned_type (int unsignedp, tree type)
       || TREE_UNSIGNED (type) == unsignedp)
     return type;
 
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
+  /* 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))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (integer_type_node))
     return unsignedp ? unsigned_type_node : integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (short_integer_type_node))
     return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (long_integer_type_node))
     return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (long_long_integer_type_node))
     return (unsignedp ? long_long_unsigned_type_node
            : long_long_integer_type_node);
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (widest_integer_literal_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (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_PRECISION (type) == TYPE_PRECISION (intTI_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (intTI_type_node))
     return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
 #endif
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (intDI_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (intDI_type_node))
     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (intSI_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (intSI_type_node))
     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (intHI_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (intHI_type_node))
     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
-  if (TYPE_PRECISION (type) == TYPE_PRECISION (intQI_type_node))
+  if (TYPE_MODE (type) == TYPE_MODE (intQI_type_node))
     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
 
   return type;
diff --git a/gcc/testsuite/g++.dg/opt/enum1.C b/gcc/testsuite/g++.dg/opt/enum1.C
new file mode 100644 (file)
index 0000000..6416b3f
--- /dev/null
@@ -0,0 +1,30 @@
+// Verify that we don't confuse precision and mode for enums.
+// { dg-do run }
+// { dg-options "-O" }
+
+extern "C" void abort();
+
+enum E {
+  zero = 0, 
+  test = 0xbb
+};
+
+static bool foo(unsigned char *x)
+{
+  E e = static_cast<E>(*x);
+  switch (e)
+    {
+    case test:
+      return true;
+    default:
+      return false;
+    }
+}
+
+int main()
+{
+  unsigned char dummy = test;
+  if (! foo(&dummy))
+    abort ();
+  return 0;
+}