public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] P0258R2 - add __has_unique_object_representations
@ 2016-10-05 20:03 Jakub Jelinek
  2016-10-06  2:43 ` Jason Merrill
  0 siblings, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2016-10-05 20:03 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

Hi!

This patch adds a compiler builtin for std::has_unique_object_representations
trait implementation.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-10-05  Jakub Jelinek  <jakub@redhat.com>

	Implement P0258R2 - helper for C++17
	std::has_unique_object_representations trait
c-family/
	* c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* c-common.c (c_common_reswords): Add
	__has_unique_object_representations.
cp/
	* cp-tree.h (enum cp_trait_kind): Add
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(struct lang_type_class): Add unique_obj_representations
	and unique_obj_representations_set bitfields.
	(CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS,
	CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET): Define.
	(type_has_unique_obj_representations): Declare.
	* parser.c (cp_parser_primary_expression): Handle
	RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(cp_parser_trait_expr): Likewise.  Formatting fix.
	* semantics.c (trait_expr_value, finish_trait_expr): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* tree.c (type_has_unique_obj_representations): New function.
	(record_has_unique_obj_representations): New function.
	* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
testsuite/
	* g++.dg/cpp1z/has-unique-obj-representations1.C: New test.
	* g++.dg/cpp1z/has-unique-obj-representations2.C: New test.

--- gcc/c-family/c-common.h.jj	2016-10-05 17:01:32.481625298 +0200
+++ gcc/c-family/c-common.h	2016-10-05 17:45:27.046478684 +0200
@@ -150,7 +150,8 @@ enum rid
   RID_HAS_NOTHROW_ASSIGN,      RID_HAS_NOTHROW_CONSTRUCTOR,
   RID_HAS_NOTHROW_COPY,        RID_HAS_TRIVIAL_ASSIGN,
   RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY,
-  RID_HAS_TRIVIAL_DESTRUCTOR,  RID_HAS_VIRTUAL_DESTRUCTOR,
+  RID_HAS_TRIVIAL_DESTRUCTOR,  RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+  RID_HAS_VIRTUAL_DESTRUCTOR,
   RID_IS_ABSTRACT,             RID_IS_BASE_OF,
   RID_IS_CLASS,
   RID_IS_EMPTY,                RID_IS_ENUM,
--- gcc/c-family/c-common.c.jj	2016-10-05 17:09:35.964394250 +0200
+++ gcc/c-family/c-common.c	2016-10-05 17:45:27.046478684 +0200
@@ -486,6 +486,8 @@ const struct c_common_resword c_common_r
   { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY },
   { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY },
   { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY },
+  { "__has_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+					D_CXXONLY },
   { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY },
   { "__imag",		RID_IMAGPART,	0 },
   { "__imag__",		RID_IMAGPART,	0 },
--- gcc/cp/cp-tree.h.jj	2016-10-05 17:01:29.898658586 +0200
+++ gcc/cp/cp-tree.h	2016-10-05 17:45:47.780211364 +0200
@@ -723,6 +723,7 @@ enum cp_trait_kind
   CPTK_HAS_TRIVIAL_CONSTRUCTOR,
   CPTK_HAS_TRIVIAL_COPY,
   CPTK_HAS_TRIVIAL_DESTRUCTOR,
+  CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS,
   CPTK_HAS_VIRTUAL_DESTRUCTOR,
   CPTK_IS_ABSTRACT,
   CPTK_IS_BASE_OF,
@@ -1713,6 +1714,8 @@ struct GTY(()) lang_type_class {
   unsigned has_complex_move_ctor : 1;
   unsigned has_complex_move_assign : 1;
   unsigned has_constexpr_ctor : 1;
+  unsigned unique_obj_representations : 1;
+  unsigned unique_obj_representations_set : 1;
 
   /* When adding a flag here, consider whether or not it ought to
      apply to a template instance if it applies to the template.  If
@@ -1721,7 +1724,7 @@ struct GTY(()) lang_type_class {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 4;
+  unsigned dummy : 2;
 
   tree primary_base;
   vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2010,6 +2013,16 @@ struct GTY(()) lang_type {
 #define CLASSTYPE_NON_STD_LAYOUT(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->non_std_layout)
 
+/* Nonzero means that this class type does have unique object
+   representations.  */
+#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations)
+
+/* Nonzero means that this class type has
+   CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS computed.  */
+#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations_set)
+
 /* Nonzero means that this class contains pod types whose default
    initialization is not a zero initialization (namely, pointers to
    data members).  */
@@ -6480,6 +6493,7 @@ extern bool layout_pod_type_p			(const_t
 extern bool std_layout_type_p			(const_tree);
 extern bool trivial_type_p			(const_tree);
 extern bool trivially_copyable_p		(const_tree);
+extern bool type_has_unique_obj_representations (const_tree);
 extern bool scalarish_type_p			(const_tree);
 extern bool type_has_nontrivial_default_init	(const_tree);
 extern bool type_has_nontrivial_copy_init	(const_tree);
--- gcc/cp/parser.c.jj	2016-10-05 17:01:29.905658496 +0200
+++ gcc/cp/parser.c	2016-10-05 17:45:27.036478813 +0200
@@ -5109,6 +5109,7 @@ cp_parser_primary_expression (cp_parser
 	case RID_HAS_TRIVIAL_CONSTRUCTOR:
 	case RID_HAS_TRIVIAL_COPY:	  
 	case RID_HAS_TRIVIAL_DESTRUCTOR:
+	case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
 	case RID_HAS_VIRTUAL_DESTRUCTOR:
 	case RID_IS_ABSTRACT:
 	case RID_IS_BASE_OF:
@@ -9520,6 +9521,9 @@ cp_parser_trait_expr (cp_parser* parser,
     case RID_HAS_TRIVIAL_DESTRUCTOR:
       kind = CPTK_HAS_TRIVIAL_DESTRUCTOR;
       break;
+    case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS;
+      break;
     case RID_HAS_VIRTUAL_DESTRUCTOR:
       kind = CPTK_HAS_VIRTUAL_DESTRUCTOR;
       break;
@@ -9634,7 +9638,7 @@ cp_parser_trait_expr (cp_parser* parser,
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch(kind)
+  switch (kind)
     {
     case CPTK_UNDERLYING_TYPE:
       return finish_underlying_type (type1);
--- gcc/cp/semantics.c.jj	2016-10-04 17:29:09.358174804 +0200
+++ gcc/cp/semantics.c	2016-10-05 17:45:27.041478748 +0200
@@ -9087,6 +9087,9 @@ trait_expr_value (cp_trait_kind kind, tr
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       return type_has_virtual_destructor (type1);
 
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      return type_has_unique_obj_representations (type1);
+
     case CPTK_IS_ABSTRACT:
       return (ABSTRACT_CLASS_TYPE_P (type1));
 
@@ -9194,6 +9197,7 @@ finish_trait_expr (cp_trait_kind kind, t
     case CPTK_HAS_NOTHROW_COPY:
     case CPTK_HAS_TRIVIAL_COPY:
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
     case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
--- gcc/cp/tree.c.jj	2016-10-04 17:30:36.323066795 +0200
+++ gcc/cp/tree.c	2016-10-05 18:52:31.270215943 +0200
@@ -3575,6 +3575,150 @@ std_layout_type_p (const_tree t)
     return scalarish_type_p (t);
 }
 
+static bool record_has_unique_obj_representations (const_tree, const_tree);
+
+/* Returns true iff T satisfies std::has_unique_object_representations<T>,
+   as defined in [meta.unary.prop].  */
+
+bool
+type_has_unique_obj_representations (const_tree t)
+{
+  bool ret;
+
+  t = strip_array_types (CONST_CAST_TREE (t));
+
+  if (!trivially_copyable_p (t))
+    return false;
+
+  if (CLASS_TYPE_P (t) && CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t))
+    return CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t);
+
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+      return TYPE_PRECISION (t) == GET_MODE_PRECISION (TYPE_MODE (t));
+
+    case BOOLEAN_TYPE:
+      /* For bool values other than 0 and 1 should only appear with
+	 undefined behavior.  */
+      return true;
+
+    case ENUMERAL_TYPE:
+      return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));
+
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      return true;
+
+    case REAL_TYPE:
+      /* XFmode certainly contains padding on x86, which the CPU doesn't store
+	 when storing long double values, so for that we have to return false.
+	 Other kinds of floating point values are questionable due to +.0/-.0
+	 and NaNs, let's play safe for now.  */
+      return false;
+
+    case FIXED_POINT_TYPE:
+      return false;
+
+    case OFFSET_TYPE:
+      return true;
+
+    case COMPLEX_TYPE:
+    case VECTOR_TYPE:
+      return type_has_unique_obj_representations (TREE_TYPE (t));
+
+    case RECORD_TYPE:
+      ret = record_has_unique_obj_representations (t, TYPE_SIZE (t));
+      if (CLASS_TYPE_P (t))
+	{
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
+	}
+      return ret;
+
+    case UNION_TYPE:
+      ret = true;
+      bool any_fields;
+      any_fields = false;
+      for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+	if (TREE_CODE (field) == FIELD_DECL)
+	  {
+	    any_fields = true;
+	    if (!type_has_unique_obj_representations (TREE_TYPE (field))
+		|| simple_cst_equal (DECL_SIZE (field), TYPE_SIZE (t)) != 1)
+	      {
+		ret = false;
+		break;
+	      }
+	  }
+      if (!any_fields && !integer_zerop (TYPE_SIZE (t)))
+	ret = false;
+      if (CLASS_TYPE_P (t))
+	{
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
+	}
+      return ret;
+
+    case NULLPTR_TYPE:
+      return false;
+
+    case ERROR_MARK:
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Helper function for type_has_unique_obj_representations.  */
+
+static bool
+record_has_unique_obj_representations (const_tree t, const_tree sz)
+{
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) != FIELD_DECL)
+      ;
+    /* For bases, can't use type_has_unique_obj_representations here, as in
+	struct S { int i : 24; S (); };
+	struct T : public S { int j : 8; T (); };
+	S doesn't have unique obj representations, but T does.  */
+    else if (DECL_FIELD_IS_BASE (field))
+      {
+	if (!record_has_unique_obj_representations (TREE_TYPE (field),
+						    DECL_SIZE (field)))
+	  return false;
+      }
+    else if (DECL_C_BIT_FIELD (field))
+      {
+	tree btype = DECL_BIT_FIELD_TYPE (field);
+	if (!type_has_unique_obj_representations (btype))
+	  return false;
+      }
+    else if (!type_has_unique_obj_representations (TREE_TYPE (field)))
+      return false;
+
+  offset_int cur = 0;
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL)
+      {
+	offset_int fld = wi::to_offset (DECL_FIELD_OFFSET (field));
+	offset_int bitpos = wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
+	fld = fld * BITS_PER_UNIT + bitpos;
+	if (cur != fld)
+	  return false;
+	if (DECL_SIZE (field))
+	  {
+	    offset_int size = wi::to_offset (DECL_SIZE (field));
+	    cur += size;
+	  }
+      }
+  if (cur != wi::to_offset (sz))
+    return false;
+
+  return true;
+}
+
 /* Nonzero iff type T is a class template implicit specialization.  */
 
 bool
--- gcc/cp/cxx-pretty-print.c.jj	2016-10-04 17:29:09.356174829 +0200
+++ gcc/cp/cxx-pretty-print.c	2016-10-05 17:45:27.043478722 +0200
@@ -2562,6 +2562,9 @@ pp_cxx_trait_expression (cxx_pretty_prin
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       pp_cxx_ws_string (pp, "__has_trivial_destructor");
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      pp_cxx_ws_string (pp, "__has_unique_object_representations");
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       pp_cxx_ws_string (pp, "__has_virtual_destructor");
       break;
--- gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C.jj	2016-10-05 18:31:08.743590778 +0200
+++ gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C	2016-10-05 19:20:47.286584521 +0200
@@ -0,0 +1,40 @@
+// { dg-do compile { target c++11 } }
+
+struct S { int i : 24; S (); };
+struct T : public S { int j : 8; T (); };
+struct U { int i : 24; int j : 8; };
+struct V { int i : 24; int j : 9; };
+struct W {};
+struct X : public W { int i; void bar (); };
+struct Y { char a[3]; char b[]; };
+struct Z { int a; float b; };
+static_assert (__has_unique_object_representations (char) == true, "");
+static_assert (__has_unique_object_representations (unsigned char) == true, "");
+static_assert (__has_unique_object_representations (int) == true, "");
+static_assert (__has_unique_object_representations (unsigned int) == true, "");
+static_assert (__has_unique_object_representations (bool) == true, "");
+#if __SIZEOF_INT__ == 4 && __CHAR_BIT__ == 8
+static_assert (__has_unique_object_representations (S) == false, "");
+static_assert (sizeof (T) != sizeof (int) || __has_unique_object_representations (T) == true, "");
+static_assert (sizeof (U) != sizeof (int) || __has_unique_object_representations (U) == true, "");
+static_assert (__has_unique_object_representations (V) == false, "");
+#endif
+static_assert (__has_unique_object_representations (W) == false, "");
+static_assert (sizeof (X) != sizeof (int) || __has_unique_object_representations (X) == true, "");
+static_assert (__has_unique_object_representations (float) == false, "");
+static_assert (__has_unique_object_representations (double) == false, "");
+static_assert (__has_unique_object_representations (long double) == false, "");
+static_assert (__has_unique_object_representations (void) == false, "");
+static_assert (__has_unique_object_representations (_Complex int) == true, "");
+static_assert (__has_unique_object_representations (_Complex float) == false, "");
+static_assert (__has_unique_object_representations (_Complex double) == false, "");
+static_assert (__has_unique_object_representations (_Complex long double) == false, "");
+static_assert (__has_unique_object_representations (int __attribute__((vector_size (16)))) == true, "");
+static_assert (__has_unique_object_representations (float __attribute__((vector_size (16)))) == false, "");
+static_assert (__has_unique_object_representations (int S::*) == true, "");
+static_assert (__has_unique_object_representations (void (X::*) ()) == true, "");
+static_assert (__has_unique_object_representations (int *) == true, "");
+static_assert (__has_unique_object_representations (int (*) ()) == true, "");
+static_assert (__has_unique_object_representations (decltype (nullptr)) == false, "");
+static_assert (__has_unique_object_representations (Y) == (sizeof (Y) == 3 * sizeof (char)), "");
+static_assert (__has_unique_object_representations (Z) == false, "");
--- gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C.jj	2016-10-05 19:17:33.865051243 +0200
+++ gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C	2016-10-05 19:17:27.000000000 +0200
@@ -0,0 +1,6 @@
+struct S;
+struct T { S t; };					// { dg-error "incomplete type" }
+struct U { int u[sizeof (S)]; };			// { dg-error "incomplete type" }
+bool a = __has_unique_object_representations (S);	// { dg-error "incomplete type" }
+bool b = __has_unique_object_representations (T);
+bool c = __has_unique_object_representations (U);

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-05 20:03 [C++ PATCH] P0258R2 - add __has_unique_object_representations Jakub Jelinek
@ 2016-10-06  2:43 ` Jason Merrill
  2016-10-06  7:26   ` Jakub Jelinek
  2016-10-06 10:05   ` Jonathan Wakely
  0 siblings, 2 replies; 9+ messages in thread
From: Jason Merrill @ 2016-10-06  2:43 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches List

On Wed, Oct 5, 2016 at 4:02 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> +    case INTEGER_TYPE:
> +      return TYPE_PRECISION (t) == GET_MODE_PRECISION (TYPE_MODE (t));
> +
> +    case BOOLEAN_TYPE:
> +      /* For bool values other than 0 and 1 should only appear with
> +        undefined behavior.  */
> +      return true;
> +
> +    case ENUMERAL_TYPE:
> +      return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));

I would think that we want the same answer for bool and enums: Either
the whole type size participates in the value representation, but only
certain values have defined behavior (so we should return true), or
only certain bits participate in the value representation (so we
should return false).  This is a question for the committee, but I'm
inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
ENUMERAL_TYPE as well, since we don't mask off the other bits when
loading one of these types.

> +    case POINTER_TYPE:
> +    case REFERENCE_TYPE:
> +      return true;

Is this true for all targets?  Aren't there some pointer modes that
only take up part of a word?

> +    else if (DECL_C_BIT_FIELD (field))
> +      {
> +       tree btype = DECL_BIT_FIELD_TYPE (field);
> +       if (!type_has_unique_obj_representations (btype))
> +         return false;
> +      }

C++ allows a bit-field to be larger than the type needs, in which case
we should return false.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06  2:43 ` Jason Merrill
@ 2016-10-06  7:26   ` Jakub Jelinek
  2016-10-06 10:05   ` Jonathan Wakely
  1 sibling, 0 replies; 9+ messages in thread
From: Jakub Jelinek @ 2016-10-06  7:26 UTC (permalink / raw)
  To: Jason Merrill, Joseph S. Myers, DJ Delorie, Nick Clifton,
	Andreas Krebbel
  Cc: Jonathan Wakely, gcc-patches List

On Wed, Oct 05, 2016 at 10:43:00PM -0400, Jason Merrill wrote:
> On Wed, Oct 5, 2016 at 4:02 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> > +    case INTEGER_TYPE:
> > +      return TYPE_PRECISION (t) == GET_MODE_PRECISION (TYPE_MODE (t));
> > +
> > +    case BOOLEAN_TYPE:
> > +      /* For bool values other than 0 and 1 should only appear with
> > +        undefined behavior.  */
> > +      return true;
> > +
> > +    case ENUMERAL_TYPE:
> > +      return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));
> 
> I would think that we want the same answer for bool and enums: Either
> the whole type size participates in the value representation, but only
> certain values have defined behavior (so we should return true), or
> only certain bits participate in the value representation (so we
> should return false).  This is a question for the committee, but I'm
> inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
> ENUMERAL_TYPE as well, since we don't mask off the other bits when
> loading one of these types.

The reason for the TYPE_PRECISION (t) == GET_MODE_PRECISION (TYPE_MODE (t))
is mainly worry about weirdo targets, as C++ only has the bitfield types
in the structures and that is handled in the other routine.  So the
expectations are that for INTEGER_TYPE/BOOLEAN_TYPE/ENUMERAL_TYPE we'll just
return true on sane architectures.  What I'm worried about is say __int24 or
similar types (I think AVR has them), but maybe even those are fine.
The problems would be like with the x86 XFmode long double, where a store of
that type doesn't occupy all the bytes.  Perhaps we can just return true
for all the 3 above and add a target hook that can override it first.

Returning true rather than false for bool has came up from lengthy IRC
discussions, if a value other than 0 or 1 ends up in those bytes, it will
be either through uninitializing those, or through e.g. using non-active
union member, or through aliasing violations.  But we don't really expect
those other values in there, e.g. for bool b; ... if (b) foo (); we
just compare the whole byte against 0 (if we did that consistently
everywhere, we could say we define bool as 0 being false and anything != 0
being true and std::has_unique_object_representations would need to return
false), but if one converts bool to say unsigned char, we don't do any
comparison, just simple assignment.

> 
> > +    case POINTER_TYPE:
> > +    case REFERENCE_TYPE:
> > +      return true;
> 
> Is this true for all targets?  Aren't there some pointer modes that
> only take up part of a word?

I'm not sure.  I'm slightly worried about s390 31-bit (where the top bit is
kind of ignored by the HW), but most likely we are fine, because we just
store all 32 bits when storing pointers, and in all normal addresses the top
bit will be clear, so it acts like bool, the upper bit in a valid program
will be 0.  And then about m32c or whatever arch has those 24-bit
pointers with size of 32-bits.  The question is, does the HW or compiler
store zeros in the remaining bits all the times, so it acts like a bool,
or are the bits real padding?

> > +    else if (DECL_C_BIT_FIELD (field))
> > +      {
> > +       tree btype = DECL_BIT_FIELD_TYPE (field);
> > +       if (!type_has_unique_obj_representations (btype))
> > +         return false;
> > +      }
> 
> C++ allows a bit-field to be larger than the type needs, in which case
> we should return false.

I'll look at this and add testcase; I wonder if it isn't caught during
the in-between field padding checks later on.  It would be if DECL_SIZE
of the bitfield is maxed at the DECL_BIT_FIELD_TYPE's bitsize, and the
remaining bits are gaps in between fields.

Reminds me to look at bitfields in unions.

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06  2:43 ` Jason Merrill
  2016-10-06  7:26   ` Jakub Jelinek
@ 2016-10-06 10:05   ` Jonathan Wakely
  2016-10-06 10:15     ` Jakub Jelinek
  1 sibling, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2016-10-06 10:05 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, gcc-patches List

On 05/10/16 22:43 -0400, Jason Merrill wrote:
>On Wed, Oct 5, 2016 at 4:02 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> +    case INTEGER_TYPE:
>> +      return TYPE_PRECISION (t) == GET_MODE_PRECISION (TYPE_MODE (t));
>> +
>> +    case BOOLEAN_TYPE:
>> +      /* For bool values other than 0 and 1 should only appear with
>> +        undefined behavior.  */
>> +      return true;
>> +
>> +    case ENUMERAL_TYPE:
>> +      return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));
>
>I would think that we want the same answer for bool and enums: Either
>the whole type size participates in the value representation, but only
>certain values have defined behavior (so we should return true), or
>only certain bits participate in the value representation (so we
>should return false).  This is a question for the committee, but I'm
>inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
>ENUMERAL_TYPE as well, since we don't mask off the other bits when
>loading one of these types.

Yes, my new, slightly improved understanding is that if the front-end
always did a mask operation when accessing enumeration types and bool
then the bits outside its valid range of values would be padding. They
would not contribute to its value if set to non-zero values e.g.  by
memset. But since we just load those values without masking, and rely
on a well-defined program not to set bits outside the valid range, we
should return true for those types.

Thanks for working on this, Jakub!

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06 10:05   ` Jonathan Wakely
@ 2016-10-06 10:15     ` Jakub Jelinek
  2016-10-06 10:54       ` Jonathan Wakely
  0 siblings, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2016-10-06 10:15 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jason Merrill, gcc-patches List

On Thu, Oct 06, 2016 at 11:05:19AM +0100, Jonathan Wakely wrote:
> >I would think that we want the same answer for bool and enums: Either
> >the whole type size participates in the value representation, but only
> >certain values have defined behavior (so we should return true), or
> >only certain bits participate in the value representation (so we
> >should return false).  This is a question for the committee, but I'm
> >inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
> >ENUMERAL_TYPE as well, since we don't mask off the other bits when
> >loading one of these types.
> 
> Yes, my new, slightly improved understanding is that if the front-end
> always did a mask operation when accessing enumeration types and bool
> then the bits outside its valid range of values would be padding. They
> would not contribute to its value if set to non-zero values e.g.  by
> memset. But since we just load those values without masking, and rely
> on a well-defined program not to set bits outside the valid range, we
> should return true for those types.

And if bool is always implemented as load of byte and comparison against 0,
then the other bits wouldn't be padding, they would participate in the
value, but it would mean the representation of true is not unique.
But as we do sometimes comparison, sometimes masking and sometimes neither,
the behavior with values other than 0/1 is really not well defined, they
just shouldn't appear in valid programs.

So, shall I just return true for INTEGER_TYPE/BOOLEAN_TYPE/ENUMERAL_TYPE
as well as POINTER_TYPE/REFERENCE_TYPE, and if some target needs something
different, add (later on if the need arises or right away?) a target hook
where target can override.

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06 10:15     ` Jakub Jelinek
@ 2016-10-06 10:54       ` Jonathan Wakely
  2016-10-06 12:46         ` Jason Merrill
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2016-10-06 10:54 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches List

On 06/10/16 12:15 +0200, Jakub Jelinek wrote:
>On Thu, Oct 06, 2016 at 11:05:19AM +0100, Jonathan Wakely wrote:
>> >I would think that we want the same answer for bool and enums: Either
>> >the whole type size participates in the value representation, but only
>> >certain values have defined behavior (so we should return true), or
>> >only certain bits participate in the value representation (so we
>> >should return false).  This is a question for the committee, but I'm
>> >inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
>> >ENUMERAL_TYPE as well, since we don't mask off the other bits when
>> >loading one of these types.
>>
>> Yes, my new, slightly improved understanding is that if the front-end
>> always did a mask operation when accessing enumeration types and bool
>> then the bits outside its valid range of values would be padding. They
>> would not contribute to its value if set to non-zero values e.g.  by
>> memset. But since we just load those values without masking, and rely
>> on a well-defined program not to set bits outside the valid range, we
>> should return true for those types.
>
>And if bool is always implemented as load of byte and comparison against 0,
>then the other bits wouldn't be padding, they would participate in the
>value, but it would mean the representation of true is not unique.
>But as we do sometimes comparison, sometimes masking and sometimes neither,
>the behavior with values other than 0/1 is really not well defined, they
>just shouldn't appear in valid programs.
>
>So, shall I just return true for INTEGER_TYPE/BOOLEAN_TYPE/ENUMERAL_TYPE
>as well as POINTER_TYPE/REFERENCE_TYPE, and if some target needs something
>different, add (later on if the need arises or right away?) a target hook
>where target can override.

That makes sense to me.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06 10:54       ` Jonathan Wakely
@ 2016-10-06 12:46         ` Jason Merrill
  2016-10-06 15:31           ` Jakub Jelinek
  0 siblings, 1 reply; 9+ messages in thread
From: Jason Merrill @ 2016-10-06 12:46 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jakub Jelinek, gcc-patches List

On Thu, Oct 6, 2016 at 6:54 AM, Jonathan Wakely <jwakely@redhat.com> wrote:
> On 06/10/16 12:15 +0200, Jakub Jelinek wrote:
>>
>> On Thu, Oct 06, 2016 at 11:05:19AM +0100, Jonathan Wakely wrote:
>>>
>>> >I would think that we want the same answer for bool and enums: Either
>>> >the whole type size participates in the value representation, but only
>>> >certain values have defined behavior (so we should return true), or
>>> >only certain bits participate in the value representation (so we
>>> >should return false).  This is a question for the committee, but I'm
>>> >inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
>>> >ENUMERAL_TYPE as well, since we don't mask off the other bits when
>>> >loading one of these types.
>>>
>>> Yes, my new, slightly improved understanding is that if the front-end
>>> always did a mask operation when accessing enumeration types and bool
>>> then the bits outside its valid range of values would be padding. They
>>> would not contribute to its value if set to non-zero values e.g.  by
>>> memset. But since we just load those values without masking, and rely
>>> on a well-defined program not to set bits outside the valid range, we
>>> should return true for those types.
>>
>> And if bool is always implemented as load of byte and comparison against 0,
>> then the other bits wouldn't be padding, they would participate in the
>> value, but it would mean the representation of true is not unique.
>> But as we do sometimes comparison, sometimes masking and sometimes neither,
>> the behavior with values other than 0/1 is really not well defined, they
>> just shouldn't appear in valid programs.
>>
>> So, shall I just return true for INTEGER_TYPE/BOOLEAN_TYPE/ENUMERAL_TYPE
>> as well as POINTER_TYPE/REFERENCE_TYPE, and if some target needs something
>> different, add (later on if the need arises or right away?) a target hook
>> where target can override.
>
> That makes sense to me.

And to me.

Jason

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06 12:46         ` Jason Merrill
@ 2016-10-06 15:31           ` Jakub Jelinek
  2016-10-06 19:45             ` Jason Merrill
  0 siblings, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2016-10-06 15:31 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches List

On Thu, Oct 06, 2016 at 08:46:26AM -0400, Jason Merrill wrote:
> >>> >I would think that we want the same answer for bool and enums: Either
> >>> >the whole type size participates in the value representation, but only
> >>> >certain values have defined behavior (so we should return true), or
> >>> >only certain bits participate in the value representation (so we
> >>> >should return false).  This is a question for the committee, but I'm
> >>> >inclined to use the INTEGER_TYPE code for BOOLEAN_TYPE and
> >>> >ENUMERAL_TYPE as well, since we don't mask off the other bits when
> >>> >loading one of these types.
> >>>
> >>> Yes, my new, slightly improved understanding is that if the front-end
> >>> always did a mask operation when accessing enumeration types and bool
> >>> then the bits outside its valid range of values would be padding. They
> >>> would not contribute to its value if set to non-zero values e.g.  by
> >>> memset. But since we just load those values without masking, and rely
> >>> on a well-defined program not to set bits outside the valid range, we
> >>> should return true for those types.
> >>
> >> And if bool is always implemented as load of byte and comparison against 0,
> >> then the other bits wouldn't be padding, they would participate in the
> >> value, but it would mean the representation of true is not unique.
> >> But as we do sometimes comparison, sometimes masking and sometimes neither,
> >> the behavior with values other than 0/1 is really not well defined, they
> >> just shouldn't appear in valid programs.
> >>
> >> So, shall I just return true for INTEGER_TYPE/BOOLEAN_TYPE/ENUMERAL_TYPE
> >> as well as POINTER_TYPE/REFERENCE_TYPE, and if some target needs something
> >> different, add (later on if the need arises or right away?) a target hook
> >> where target can override.
> >
> > That makes sense to me.
> 
> And to me.

Ok, here is the updated patch, without addition of the target hook (until we
know for sure we need it).  I've added further testsuite coverage to check
the oversized bitfields, they actually work even with the old code due to
their DECL_SIZE being the actual underlying type's DECL_SIZE and then just
padding gap.

Bootstrap/regtest pending, ok for trunk if it succeeds?

2016-10-06  Jakub Jelinek  <jakub@redhat.com>

	Implement P0258R2 - helper for C++17
	std::has_unique_object_representations trait
c-family/
	* c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* c-common.c (c_common_reswords): Add
	__has_unique_object_representations.
cp/
	* cp-tree.h (enum cp_trait_kind): Add
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(struct lang_type_class): Add unique_obj_representations
	and unique_obj_representations_set bitfields.
	(CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS,
	CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET): Define.
	(type_has_unique_obj_representations): Declare.
	* parser.c (cp_parser_primary_expression): Handle
	RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	(cp_parser_trait_expr): Likewise.  Formatting fix.
	* semantics.c (trait_expr_value, finish_trait_expr): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
	* tree.c (type_has_unique_obj_representations): New function.
	(record_has_unique_obj_representations): New function.
	* cxx-pretty-print.c (pp_cxx_trait_expression): Handle
	CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS.
testsuite/
	* g++.dg/cpp1z/has-unique-obj-representations1.C: New test.
	* g++.dg/cpp1z/has-unique-obj-representations2.C: New test.

--- gcc/c-family/c-common.h.jj	2016-10-06 14:26:18.217598064 +0200
+++ gcc/c-family/c-common.h	2016-10-06 16:06:00.361315374 +0200
@@ -151,7 +151,8 @@ enum rid
   RID_HAS_NOTHROW_ASSIGN,      RID_HAS_NOTHROW_CONSTRUCTOR,
   RID_HAS_NOTHROW_COPY,        RID_HAS_TRIVIAL_ASSIGN,
   RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY,
-  RID_HAS_TRIVIAL_DESTRUCTOR,  RID_HAS_VIRTUAL_DESTRUCTOR,
+  RID_HAS_TRIVIAL_DESTRUCTOR,  RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+  RID_HAS_VIRTUAL_DESTRUCTOR,
   RID_IS_ABSTRACT,             RID_IS_BASE_OF,
   RID_IS_CLASS,
   RID_IS_EMPTY,                RID_IS_ENUM,
--- gcc/c-family/c-common.c.jj	2016-10-06 14:25:30.158207635 +0200
+++ gcc/c-family/c-common.c	2016-10-06 16:06:00.364315336 +0200
@@ -487,6 +487,8 @@ const struct c_common_resword c_common_r
   { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, D_CXXONLY },
   { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, D_CXXONLY },
   { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, D_CXXONLY },
+  { "__has_unique_object_representations", RID_HAS_UNIQUE_OBJ_REPRESENTATIONS,
+					D_CXXONLY },
   { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, D_CXXONLY },
   { "__imag",		RID_IMAGPART,	0 },
   { "__imag__",		RID_IMAGPART,	0 },
--- gcc/cp/cp-tree.h.jj	2016-10-06 15:19:29.254072523 +0200
+++ gcc/cp/cp-tree.h	2016-10-06 16:06:00.366315311 +0200
@@ -723,6 +723,7 @@ enum cp_trait_kind
   CPTK_HAS_TRIVIAL_CONSTRUCTOR,
   CPTK_HAS_TRIVIAL_COPY,
   CPTK_HAS_TRIVIAL_DESTRUCTOR,
+  CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS,
   CPTK_HAS_VIRTUAL_DESTRUCTOR,
   CPTK_IS_ABSTRACT,
   CPTK_IS_BASE_OF,
@@ -1713,6 +1714,8 @@ struct GTY(()) lang_type_class {
   unsigned has_complex_move_ctor : 1;
   unsigned has_complex_move_assign : 1;
   unsigned has_constexpr_ctor : 1;
+  unsigned unique_obj_representations : 1;
+  unsigned unique_obj_representations_set : 1;
 
   /* When adding a flag here, consider whether or not it ought to
      apply to a template instance if it applies to the template.  If
@@ -1721,7 +1724,7 @@ struct GTY(()) lang_type_class {
   /* There are some bits left to fill out a 32-bit word.  Keep track
      of this by updating the size of this bitfield whenever you add or
      remove a flag.  */
-  unsigned dummy : 4;
+  unsigned dummy : 2;
 
   tree primary_base;
   vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2010,6 +2013,16 @@ struct GTY(()) lang_type {
 #define CLASSTYPE_NON_STD_LAYOUT(NODE) \
   (LANG_TYPE_CLASS_CHECK (NODE)->non_std_layout)
 
+/* Nonzero means that this class type does have unique object
+   representations.  */
+#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations)
+
+/* Nonzero means that this class type has
+   CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS computed.  */
+#define CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET(NODE) \
+  (LANG_TYPE_CLASS_CHECK (NODE)->unique_obj_representations_set)
+
 /* Nonzero means that this class contains pod types whose default
    initialization is not a zero initialization (namely, pointers to
    data members).  */
@@ -6481,6 +6494,7 @@ extern bool layout_pod_type_p			(const_t
 extern bool std_layout_type_p			(const_tree);
 extern bool trivial_type_p			(const_tree);
 extern bool trivially_copyable_p		(const_tree);
+extern bool type_has_unique_obj_representations (const_tree);
 extern bool scalarish_type_p			(const_tree);
 extern bool type_has_nontrivial_default_init	(const_tree);
 extern bool type_has_nontrivial_copy_init	(const_tree);
--- gcc/cp/parser.c.jj	2016-10-06 14:55:56.163032446 +0200
+++ gcc/cp/parser.c	2016-10-06 16:06:00.375315196 +0200
@@ -5110,6 +5110,7 @@ cp_parser_primary_expression (cp_parser
 	case RID_HAS_TRIVIAL_CONSTRUCTOR:
 	case RID_HAS_TRIVIAL_COPY:	  
 	case RID_HAS_TRIVIAL_DESTRUCTOR:
+	case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
 	case RID_HAS_VIRTUAL_DESTRUCTOR:
 	case RID_IS_ABSTRACT:
 	case RID_IS_BASE_OF:
@@ -9532,6 +9533,9 @@ cp_parser_trait_expr (cp_parser* parser,
     case RID_HAS_TRIVIAL_DESTRUCTOR:
       kind = CPTK_HAS_TRIVIAL_DESTRUCTOR;
       break;
+    case RID_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      kind = CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS;
+      break;
     case RID_HAS_VIRTUAL_DESTRUCTOR:
       kind = CPTK_HAS_VIRTUAL_DESTRUCTOR;
       break;
@@ -9646,7 +9650,7 @@ cp_parser_trait_expr (cp_parser* parser,
 
   /* Complete the trait expression, which may mean either processing
      the trait expr now or saving it for template instantiation.  */
-  switch(kind)
+  switch (kind)
     {
     case CPTK_UNDERLYING_TYPE:
       return finish_underlying_type (type1);
--- gcc/cp/semantics.c.jj	2016-10-06 15:43:12.762978280 +0200
+++ gcc/cp/semantics.c	2016-10-06 16:06:00.377315171 +0200
@@ -9113,6 +9113,9 @@ trait_expr_value (cp_trait_kind kind, tr
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       return type_has_virtual_destructor (type1);
 
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      return type_has_unique_obj_representations (type1);
+
     case CPTK_IS_ABSTRACT:
       return (ABSTRACT_CLASS_TYPE_P (type1));
 
@@ -9220,6 +9223,7 @@ finish_trait_expr (cp_trait_kind kind, t
     case CPTK_HAS_NOTHROW_COPY:
     case CPTK_HAS_TRIVIAL_COPY:
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
     case CPTK_IS_ABSTRACT:
     case CPTK_IS_EMPTY:
--- gcc/cp/tree.c.jj	2016-10-05 19:36:59.103212746 +0200
+++ gcc/cp/tree.c	2016-10-06 16:17:05.491850731 +0200
@@ -3575,6 +3575,150 @@ std_layout_type_p (const_tree t)
     return scalarish_type_p (t);
 }
 
+static bool record_has_unique_obj_representations (const_tree, const_tree);
+
+/* Returns true iff T satisfies std::has_unique_object_representations<T>,
+   as defined in [meta.unary.prop].  */
+
+bool
+type_has_unique_obj_representations (const_tree t)
+{
+  bool ret;
+
+  t = strip_array_types (CONST_CAST_TREE (t));
+
+  if (!trivially_copyable_p (t))
+    return false;
+
+  if (CLASS_TYPE_P (t) && CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t))
+    return CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t);
+
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      /* If some backend has any paddings in these types, we should add
+	 a target hook for this and handle it there.  */
+      return true;
+
+    case BOOLEAN_TYPE:
+      /* For bool values other than 0 and 1 should only appear with
+	 undefined behavior.  */
+      return true;
+
+    case ENUMERAL_TYPE:
+      return type_has_unique_obj_representations (ENUM_UNDERLYING_TYPE (t));
+
+    case REAL_TYPE:
+      /* XFmode certainly contains padding on x86, which the CPU doesn't store
+	 when storing long double values, so for that we have to return false.
+	 Other kinds of floating point values are questionable due to +.0/-.0
+	 and NaNs, let's play safe for now.  */
+      return false;
+
+    case FIXED_POINT_TYPE:
+      return false;
+
+    case OFFSET_TYPE:
+      return true;
+
+    case COMPLEX_TYPE:
+    case VECTOR_TYPE:
+      return type_has_unique_obj_representations (TREE_TYPE (t));
+
+    case RECORD_TYPE:
+      ret = record_has_unique_obj_representations (t, TYPE_SIZE (t));
+      if (CLASS_TYPE_P (t))
+	{
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
+	}
+      return ret;
+
+    case UNION_TYPE:
+      ret = true;
+      bool any_fields;
+      any_fields = false;
+      for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+	if (TREE_CODE (field) == FIELD_DECL)
+	  {
+	    any_fields = true;
+	    if (!type_has_unique_obj_representations (TREE_TYPE (field))
+		|| simple_cst_equal (DECL_SIZE (field), TYPE_SIZE (t)) != 1)
+	      {
+		ret = false;
+		break;
+	      }
+	  }
+      if (!any_fields && !integer_zerop (TYPE_SIZE (t)))
+	ret = false;
+      if (CLASS_TYPE_P (t))
+	{
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS_SET (t) = 1;
+	  CLASSTYPE_UNIQUE_OBJ_REPRESENTATIONS (t) = ret;
+	}
+      return ret;
+
+    case NULLPTR_TYPE:
+      return false;
+
+    case ERROR_MARK:
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Helper function for type_has_unique_obj_representations.  */
+
+static bool
+record_has_unique_obj_representations (const_tree t, const_tree sz)
+{
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) != FIELD_DECL)
+      ;
+    /* For bases, can't use type_has_unique_obj_representations here, as in
+	struct S { int i : 24; S (); };
+	struct T : public S { int j : 8; T (); };
+	S doesn't have unique obj representations, but T does.  */
+    else if (DECL_FIELD_IS_BASE (field))
+      {
+	if (!record_has_unique_obj_representations (TREE_TYPE (field),
+						    DECL_SIZE (field)))
+	  return false;
+      }
+    else if (DECL_C_BIT_FIELD (field))
+      {
+	tree btype = DECL_BIT_FIELD_TYPE (field);
+	if (!type_has_unique_obj_representations (btype))
+	  return false;
+      }
+    else if (!type_has_unique_obj_representations (TREE_TYPE (field)))
+      return false;
+
+  offset_int cur = 0;
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL)
+      {
+	offset_int fld = wi::to_offset (DECL_FIELD_OFFSET (field));
+	offset_int bitpos = wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
+	fld = fld * BITS_PER_UNIT + bitpos;
+	if (cur != fld)
+	  return false;
+	if (DECL_SIZE (field))
+	  {
+	    offset_int size = wi::to_offset (DECL_SIZE (field));
+	    cur += size;
+	  }
+      }
+  if (cur != wi::to_offset (sz))
+    return false;
+
+  return true;
+}
+
 /* Nonzero iff type T is a class template implicit specialization.  */
 
 bool
--- gcc/cp/cxx-pretty-print.c.jj	2016-10-06 15:41:49.232040043 +0200
+++ gcc/cp/cxx-pretty-print.c	2016-10-06 16:06:00.379315145 +0200
@@ -2561,6 +2561,9 @@ pp_cxx_trait_expression (cxx_pretty_prin
     case CPTK_HAS_TRIVIAL_DESTRUCTOR:
       pp_cxx_ws_string (pp, "__has_trivial_destructor");
       break;
+    case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+      pp_cxx_ws_string (pp, "__has_unique_object_representations");
+      break;
     case CPTK_HAS_VIRTUAL_DESTRUCTOR:
       pp_cxx_ws_string (pp, "__has_virtual_destructor");
       break;
--- gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C.jj	2016-10-06 16:06:00.380315133 +0200
+++ gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C	2016-10-06 16:54:53.131906764 +0200
@@ -0,0 +1,47 @@
+// { dg-do compile { target c++11 } }
+
+#define INTB (__SIZEOF_INT__ * __CHAR_BIT__)
+struct S { int i : INTB * 3 / 4; S (); };
+struct T : public S { int j : INTB / 4; T (); };
+struct U { int i : INTB * 3 / 4; int j : INTB / 4; };
+struct V { int i : INTB * 3 / 4; int j : INTB / 4 + 1; };
+struct W {};
+struct X : public W { int i; void bar (); };
+struct Y { char a[3]; char b[]; };
+struct Z { int a; float b; };
+struct A { int i : INTB * 2; int j; };			// { dg-warning "exceeds its type" }
+union B { long a; unsigned long b; };
+union C { int a; int b : INTB - 1; };
+struct D { int a : INTB + 1; int b : INTB - 1; };	// { dg-warning "exceeds its type" }
+static_assert (__has_unique_object_representations (char) == true, "");
+static_assert (__has_unique_object_representations (unsigned char) == true, "");
+static_assert (__has_unique_object_representations (int) == true, "");
+static_assert (__has_unique_object_representations (unsigned int) == true, "");
+static_assert (__has_unique_object_representations (bool) == true, "");
+static_assert (sizeof (S) != sizeof (int) || __has_unique_object_representations (S) == false, "");
+static_assert (sizeof (T) != sizeof (int) || __has_unique_object_representations (T) == true, "");
+static_assert (sizeof (U) != sizeof (int) || __has_unique_object_representations (U) == true, "");
+static_assert (__has_unique_object_representations (V) == false, "");
+static_assert (__has_unique_object_representations (W) == false, "");
+static_assert (sizeof (X) != sizeof (int) || __has_unique_object_representations (X) == true, "");
+static_assert (__has_unique_object_representations (float) == false, "");
+static_assert (__has_unique_object_representations (double) == false, "");
+static_assert (__has_unique_object_representations (long double) == false, "");
+static_assert (__has_unique_object_representations (void) == false, "");
+static_assert (__has_unique_object_representations (_Complex int) == true, "");
+static_assert (__has_unique_object_representations (_Complex float) == false, "");
+static_assert (__has_unique_object_representations (_Complex double) == false, "");
+static_assert (__has_unique_object_representations (_Complex long double) == false, "");
+static_assert (__has_unique_object_representations (int __attribute__((vector_size (16)))) == true, "");
+static_assert (__has_unique_object_representations (float __attribute__((vector_size (16)))) == false, "");
+static_assert (__has_unique_object_representations (int X::*) == true, "");
+static_assert (__has_unique_object_representations (void (X::*) ()) == true, "");
+static_assert (__has_unique_object_representations (int *) == true, "");
+static_assert (__has_unique_object_representations (int (*) ()) == true, "");
+static_assert (__has_unique_object_representations (decltype (nullptr)) == false, "");
+static_assert (__has_unique_object_representations (Y) == (sizeof (Y) == 3 * sizeof (char)), "");
+static_assert (__has_unique_object_representations (Z) == false, "");
+static_assert (__has_unique_object_representations (A) == false, "");
+static_assert (sizeof (B) != sizeof (long) || __has_unique_object_representations (B) == true, "");
+static_assert (__has_unique_object_representations (C) == false, "");
+static_assert (__has_unique_object_representations (D) == false, "");
--- gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C.jj	2016-10-06 16:06:00.380315133 +0200
+++ gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C	2016-10-06 16:29:43.051191257 +0200
@@ -0,0 +1,8 @@
+struct S;
+struct T { S t; };					// { dg-error "incomplete type" }
+struct U { int u[sizeof (S)]; };			// { dg-error "incomplete type" }
+union V { char c; char d[]; };				// { dg-error "flexible array member in union" }
+bool a = __has_unique_object_representations (S);	// { dg-error "incomplete type" }
+bool b = __has_unique_object_representations (T);
+bool c = __has_unique_object_representations (U);
+bool d = __has_unique_object_representations (V);

	Jakub

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [C++ PATCH] P0258R2 - add __has_unique_object_representations
  2016-10-06 15:31           ` Jakub Jelinek
@ 2016-10-06 19:45             ` Jason Merrill
  0 siblings, 0 replies; 9+ messages in thread
From: Jason Merrill @ 2016-10-06 19:45 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches List

OK.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-10-06 19:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-05 20:03 [C++ PATCH] P0258R2 - add __has_unique_object_representations Jakub Jelinek
2016-10-06  2:43 ` Jason Merrill
2016-10-06  7:26   ` Jakub Jelinek
2016-10-06 10:05   ` Jonathan Wakely
2016-10-06 10:15     ` Jakub Jelinek
2016-10-06 10:54       ` Jonathan Wakely
2016-10-06 12:46         ` Jason Merrill
2016-10-06 15:31           ` Jakub Jelinek
2016-10-06 19:45             ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).