Implement P0258R2 - helper for C++17 std::has_unique_object_representations trait...
authorJakub Jelinek <jakub@redhat.com>
Thu, 6 Oct 2016 21:17:44 +0000 (23:17 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 6 Oct 2016 21:17:44 +0000 (23:17 +0200)
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.

From-SVN: r240843

12 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C [new file with mode: 0644]

index 6474a6dd6f64ec97240f511de722975aa2d18818..7881233f94cd2898397920f104be75b3b4f47606 100644 (file)
@@ -1,3 +1,11 @@
+2016-10-06  Jakub Jelinek  <jakub@redhat.com>
+
+       Implement P0258R2 - helper for C++17
+       std::has_unique_object_representations trait
+       * c-common.h (enum rid): Add RID_HAS_UNIQUE_OBJ_REPRESENTATIONS.
+       * c-common.c (c_common_reswords): Add
+       __has_unique_object_representations.
+
 2016-10-05  Jakub Jelinek  <jakub@redhat.com>
 
        PR sanitizer/66343
index 035afbceeb8c82979a616a22dc412549cb241cf2..f518c20797f53923fa4a0b68e0d29a63f5277203 100644 (file)
@@ -486,6 +486,8 @@ const struct c_common_resword c_common_reswords[] =
   { "__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 },
index 28aebec6e2e2d43a3d5ef9e4dbd5abee8eaf0246..f9ebb5bca2f02df218bd3368fc5d942a783d4224 100644 (file)
@@ -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,
index 7bd7db64f4efc0751e07180fb93c9fee845bdee8..008d6461acffe56c2214dd780654b43b867156f2 100644 (file)
@@ -1,3 +1,24 @@
+2016-10-06  Jakub Jelinek  <jakub@redhat.com>
+
+       Implement P0258R2 - helper for C++17
+       std::has_unique_object_representations trait
+       * 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.
+
 2016-10-05  Jason Merrill  <jason@redhat.com>
 
        Implement P0135R1, Guaranteed copy elision.
index 92e40170f5b5a20c2bef6d700f051082ff29c147..49cbdf26fcfa6924cec41784b7e8fa8045621558 100644 (file)
@@ -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_tree);
 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);
index a290c87a9dd01e8a70446c5db584f24ef0d21e9b..68dcf58ea1ceaf264bcf61013ae61f39e382599f 100644 (file)
@@ -2561,6 +2561,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
     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;
index 60bbf49883c0f0dd04be667720dd6414e5d0f2cc..c2bd4421e14ec638ca3b2f7991b00f6b571f3c48 100644 (file)
@@ -5110,6 +5110,7 @@ cp_parser_primary_expression (cp_parser *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:
@@ -9521,6 +9522,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     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;
@@ -9635,7 +9639,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
 
   /* 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);
index 1b19f600cb7e23d7dcbf9579dc105d205cb9673d..968f88b3c04bf1dbb22e37c5faaebadc4fed3b69 100644 (file)
@@ -9092,6 +9092,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
     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));
 
@@ -9199,6 +9202,7 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
     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:
index c3853e370d199262e6b4dd7ba4d4ef6d7e2e1ac1..03eef0030d07d29f5854c85faf452e566c94c794 100644 (file)
@@ -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
index 24026c80d47e155d671f55e6ac6e8326061485ba..9aee1b289eac8c19d9f805007a5f2cee07d3f108 100644 (file)
@@ -1,3 +1,8 @@
+2016-10-06  Jakub Jelinek  <jakub@redhat.com>
+
+       * g++.dg/cpp1z/has-unique-obj-representations1.C: New test.
+       * g++.dg/cpp1z/has-unique-obj-representations2.C: New test.
+
 2016-10-06  Kugan Vivekanandarajah  <kuganv@linaro.org>
 
        PR tree-optimization/77862
diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations1.C
new file mode 100644 (file)
index 0000000..73d80bf
--- /dev/null
@@ -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, "");
diff --git a/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C b/gcc/testsuite/g++.dg/cpp1z/has-unique-obj-representations2.C
new file mode 100644 (file)
index 0000000..c4ae555
--- /dev/null
@@ -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);