Here, if cp_perform_integral_promotions saw that the TREE_TYPE of a
bit-field reference was the same as the type it promotes to, it didn't do
anything.  But then decay_conversion saw that the bit-field reference was
unchanged, and converted it to its declared type.  So I needed to add
something to make it clear that promotion has been done.  But then the 33819
change caused trouble by looking through the NOP_EXPR I just added.  This
was the wrong fix for that bug; I've now fixed that better by recognizing in
cp_perform_integral_promotions that we won't promote a bit-field larger than
32 bits, so we should use the declared type.

Tested x86_64-pc-linux-gnu, applying to trunk.

        PR c++/33819 - long bit-field promotion.
        * typeck.c (cp_perform_integral_promotions): Handle large bit-fields
        properly.  Handle 32-bit non-int bit-fields properly.
        (is_bitfield_expr_with_lowered_type): Don't look through NOP_EXPR.
---
 gcc/cp/typeck.c                        | 29 ++++++++++++++++----------
 gcc/testsuite/g++.dg/expr/bitfield14.C | 17 +++++++++++++++
 gcc/cp/ChangeLog                       |  6 ++++++
 3 files changed, 41 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/expr/bitfield14.C

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 620f2c9afdf..c6bf41ee7a4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1971,12 +1971,6 @@ is_bitfield_expr_with_lowered_type (const_tree exp)
       else
        return NULL_TREE;
 
-    CASE_CONVERT:
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp, 0)))
-         == TYPE_MAIN_VARIANT (TREE_TYPE (exp)))
-       return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
-      /* Fallthrough.  */
-
     default:
       return NULL_TREE;
     }
@@ -2189,13 +2183,23 @@ cp_perform_integral_promotions (tree expr, 
tsubst_flags_t complain)
   if (error_operand_p (expr))
     return error_mark_node;
 
+  type = TREE_TYPE (expr);
+
   /* [conv.prom]
 
-     If the bitfield has an enumerated type, it is treated as any
-     other value of that type for promotion purposes.  */
-  type = is_bitfield_expr_with_lowered_type (expr);
-  if (!type || TREE_CODE (type) != ENUMERAL_TYPE)
-    type = TREE_TYPE (expr);
+     A prvalue for an integral bit-field (11.3.9) can be converted to a prvalue
+     of type int if int can represent all the values of the bit-field;
+     otherwise, it can be converted to unsigned int if unsigned int can
+     represent all the values of the bit-field. If the bit-field is larger yet,
+     no integral promotion applies to it. If the bit-field has an enumerated
+     type, it is treated as any other value of that type for promotion
+     purposes.  */
+  tree bitfield_type = is_bitfield_expr_with_lowered_type (expr);
+  if (bitfield_type
+      && (TREE_CODE (bitfield_type) == ENUMERAL_TYPE
+         || TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node)))
+    type = bitfield_type;
+
   gcc_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type));
   /* Scoped enums don't promote.  */
   if (SCOPED_ENUM_P (type))
@@ -2203,6 +2207,9 @@ cp_perform_integral_promotions (tree expr, tsubst_flags_t 
complain)
   promoted_type = type_promotes_to (type);
   if (type != promoted_type)
     expr = cp_convert (promoted_type, expr, complain);
+  else if (bitfield_type && bitfield_type != type)
+    /* Prevent decay_conversion from converting to bitfield_type.  */
+    expr = build_nop (type, expr);
   return expr;
 }
 
diff --git a/gcc/testsuite/g++.dg/expr/bitfield14.C 
b/gcc/testsuite/g++.dg/expr/bitfield14.C
new file mode 100644
index 00000000000..546af85ba10
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/bitfield14.C
@@ -0,0 +1,17 @@
+// PR c++/30277
+// { dg-do compile { target c++11 } }
+
+struct S
+{
+  signed long l: 32;
+};
+
+void foo(long) = delete;
+void foo(int) {}
+
+int main()
+{
+  S x = {1};
+  foo(x.l+0);
+  return 0;
+}
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index bed72c90a2e..7bf28f81fae 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,11 @@
 2019-09-15  Jason Merrill  <ja...@redhat.com>
 
+       PR c++/30277 - int-width bit-field promotion.
+       PR c++/33819 - long bit-field promotion.
+       * typeck.c (cp_perform_integral_promotions): Handle large bit-fields
+       properly.  Handle 32-bit non-int bit-fields properly.
+       (is_bitfield_expr_with_lowered_type): Don't look through NOP_EXPR.
+
        PR c++/82165 - enum bitfields and operator overloading.
        * call.c (build_new_op_1): Use unlowered_expr_type.
 
-- 
2.21.0

Reply via email to