This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] 79118 bitfields & constexpr


This patch addresses 79118, where we ICE on a constexpr involving bitfields in an unnamed struct (unnamed struct members are a g++ extension).

This is really a band-aid, because our internal representation BITFIELD_REF and the (premature) optimizations it encourages is incompatible with constexpr requirements. There's already signs of that with Jakub's code to deal with fold turning things like:
  int foo: 5;
  int baz: 3;
...
  ptr->baz == cst
turns into the moral equivalent of (little endian example)
  ((*(unsigned char *)ptr & 0xe0) == (cst << 5)

In this particular case we've also made the base object the containing class, not the unnamed struct member. That means we're looking in the wrong CONSTRUCTOR and see CONSTRUCTOR_NO_IMPLICIT_ZERO is true. Whereas for the subobj's CONSTRUCTOR it is false. With this patch we end up thinking this is an OK constexpr of value zero, whereas it's actually an uninitialized bitfield read.

But I think we could already make that mistake given the above example & fold's behaviour. If 'ptr->foo' has been initialized, we'll construct a value using just that field and think we have a valid initialization of ptr->baz too.

The equivalent testcase using non-bitfields has a base object of the unnamed struct member, and behaves correctly (given this is an extension anyway).

The right solution is to fix the IR. In the C++ FE have BITFIELD_REF (or a new node) look much more like COMPONENT_REF (or even be COMPONENT_REF, but I suspect lots of places think ADDR (COMPONENT_REF (...)) is legit). And lower it to the middle-end generic representation in cp_genericize. I don't think this is the right time for a change of that magnitude though.

Perhaps for now we should just always err on the side of safety, and behave as-if uninitialized if we fall of the end of looking for a bitfield?

thoughts?

nathan
--
Nathan Sidwell
2017-01-23  Nathan Sidwell  <nathan@acm.org>

	PR c++/79118 - bitfields and constexpr
	* constexpr.c (cxx_eval_bitfield): Return zero or set non-constant
	if no bitfield found.

	PR c++/79118
	* g++.dg/cpp0x/pr79118.C: New.

Index: cp/constexpr.c
===================================================================
--- cp/constexpr.c	(revision 244728)
+++ cp/constexpr.c	(working copy)
@@ -2447,6 +2447,11 @@ cxx_eval_bit_field_ref (const constexpr_
       tree bitpos = bit_position (field);
       if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1))
 	return value;
+
+      /* fold likes to change bitfield accesses into byte-friendly
+	 sizes and adding explicit masking. If this field is within
+	 the range of bits being extracted, accumulate into
+	 retval.  */
       if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE
 	  && TREE_CODE (value) == INTEGER_CST
 	  && tree_fits_shwi_p (bitpos)
@@ -2476,8 +2481,31 @@ cxx_eval_bit_field_ref (const constexpr_
     }
   if (fld_seen)
     return fold_convert (TREE_TYPE (t), retval);
-  gcc_unreachable ();
-  return error_mark_node;
+
+  if (CONSTRUCTOR_NO_IMPLICIT_ZERO (whole))
+    {
+      if (!ctx->quiet)
+	{
+	  /* Find the bitfield for a useful error message.  */
+	  for (field = TYPE_FIELDS (TREE_TYPE (TREE_OPERAND (t, 0)));
+	       field; field = TREE_CHAIN (field))
+	    if (TREE_CODE (field) == FIELD_DECL
+		&& DECL_SIZE (field) == TREE_OPERAND (t, 1)
+		&& bit_position (field) == start)
+	      break;
+	  if (field)
+	    error ("accessing uninitialized bitfield %qD", field);
+	  else
+	    error ("accessing uninitialized bitfield");
+	}
+      *non_constant_p = true;
+      return t;
+    }
+
+  /* If there's no explicit init for this field, it's value-initialized.  */
+  value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
+  return cxx_eval_constant_expression (ctx, value, lval,
+				       non_constant_p, overflow_p);
 }
 
 /* Subroutine of cxx_eval_constant_expression.
Index: testsuite/g++.dg/cpp0x/pr79118.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr79118.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/pr79118.C	(working copy)
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-std=c++11" }
+// PR c++/79118 ICE with uninitialized bit field
+
+struct Impl {
+  struct {
+    char raw;
+    char type : 2;
+  };
+
+  constexpr Impl () : raw () {}
+
+  constexpr bool get () { return type; }
+};
+
+void Foo ()
+{
+  !Impl().get();
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]