summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2016-02-04 22:17:05 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2016-02-04 22:17:05 +0000
commit6b098e91f55238b31ed7eb28741ef1b96d198046 (patch)
tree0c6d6e6c7c4474708b293d53101ea2650fe22948
parent931b245017ca1b7260d2309fd6421428571870e0 (diff)
downloadgcc-6b098e91f55238b31ed7eb28741ef1b96d198046.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233154 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c/ChangeLog6
-rw-r--r--gcc/c/c-decl.c31
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/c-c++-common/pr69669.c10
4 files changed, 40 insertions, 12 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 606b63c7294..931e51d03d8 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,9 @@
+2016-02-04 Jakub Jelinek <jakub@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.
+
2016-01-29 Jakub Jelinek <jakub@redhat.com>
PR debug/69518
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index aaccaa88006..5f6f3ee2ad7 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -8037,7 +8037,24 @@ finish_enum (tree enumtype, tree values, tree attributes)
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, tree attributes)
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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5d6bec01d65..924b0fbefb5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-02-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/69669
+ * c-c++-common/pr69669.c: New test.
+
2016-02-04 Michael Meissner <meissner@linux.vnet.ibm.com>
PR target/69667
diff --git a/gcc/testsuite/c-c++-common/pr69669.c b/gcc/testsuite/c-c++-common/pr69669.c
new file mode 100644
index 00000000000..9940afe8ffb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr69669.c
@@ -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;
+}