PR c++/30277 - int-width bit-field promotion.
authorJason Merrill <jason@redhat.com>
Mon, 16 Sep 2019 04:34:28 +0000 (00:34 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 16 Sep 2019 04:34:28 +0000 (00:34 -0400)
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.

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.

From-SVN: r275746

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/g++.dg/expr/bitfield14.C [new file with mode: 0644]

index bed72c90a2ec36971801342e34d4e92bfce10bff..7bf28f81faea86ca8892d4bc355c810657495de2 100644 (file)
@@ -1,5 +1,11 @@
 2019-09-15  Jason Merrill  <jason@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.
 
index 620f2c9afdf18e00dc9f86955ba38c0244e40578..c6bf41ee7a4e8f06b8d55161d2e509fd9c3b406e 100644 (file)
@@ -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 (file)
index 0000000..546af85
--- /dev/null
@@ -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;
+}