Implement D1907R1 "structural type".
authorJason Merrill <jason@redhat.com>
Thu, 7 Nov 2019 00:50:19 +0000 (19:50 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 7 Nov 2019 00:50:19 +0000 (19:50 -0500)
ISO C++ paper D1907R1 proposes "structural type" as an alternative to the
current notion of "strong structural equality", which has various problems.
I'm implementing it to give people a chance to try it.

The build_base_field changes are to make it easier for structural_type_p to
see whether a base is private or protected.

* tree.c (structural_type_p): New.
* pt.c (invalid_nontype_parm_type_p): Use it.
* class.c (build_base_field_1): Take binfo.  Copy TREE_PRIVATE.
(build_base_field): Pass binfo.

From-SVN: r277902

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C

index 8f6a71a8b6ad1069cd7db7113f02364a31e4b5f1..a0b93e77e4de2357dcc2f8d3eb150fad2b83af80 100644 (file)
@@ -1,5 +1,11 @@
 2019-11-06  Jason Merrill  <jason@redhat.com>
 
+       Implement D1907R1 "structural type".
+       * tree.c (structural_type_p): New.
+       * pt.c (invalid_nontype_parm_type_p): Use it.
+       * class.c (build_base_field_1): Take binfo.  Copy TREE_PRIVATE.
+       (build_base_field): Pass binfo.
+
        PR c++/92150 - partial specialization with class NTTP.
        * pt.c (unify): Handle VIEW_CONVERT_EXPR.
 
index 89ed1c040f608e7ada985b1db3c7440530913976..a9aa5e77171037767036ce1ea8ac5e0cfa75108b 100644 (file)
@@ -4353,15 +4353,18 @@ layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl,
    fields at NEXT_FIELD, and return it.  */
 
 static tree
-build_base_field_1 (tree t, tree basetype, tree *&next_field)
+build_base_field_1 (tree t, tree binfo, tree *&next_field)
 {
   /* Create the FIELD_DECL.  */
+  tree basetype = BINFO_TYPE (binfo);
   gcc_assert (CLASSTYPE_AS_BASE (basetype));
   tree decl = build_decl (input_location,
                          FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype));
   DECL_ARTIFICIAL (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
   DECL_FIELD_CONTEXT (decl) = t;
+  TREE_PRIVATE (decl) = TREE_PRIVATE (binfo);
+  TREE_PROTECTED (decl) = TREE_PROTECTED (binfo);
   if (is_empty_class (basetype))
     /* CLASSTYPE_SIZE is one byte, but the field needs to have size zero.  */
     DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = size_zero_node;
@@ -4414,7 +4417,7 @@ build_base_field (record_layout_info rli, tree binfo,
       CLASSTYPE_EMPTY_P (t) = 0;
 
       /* Create the FIELD_DECL.  */
-      decl = build_base_field_1 (t, basetype, next_field);
+      decl = build_base_field_1 (t, binfo, next_field);
 
       /* Try to place the field.  It may take more than one try if we
         have a hard time placing the field without putting two
@@ -4448,7 +4451,7 @@ build_base_field (record_layout_info rli, tree binfo,
         aggregate bases.  */
       if (cxx_dialect >= cxx17 && !BINFO_VIRTUAL_P (binfo))
        {
-         tree decl = build_base_field_1 (t, basetype, next_field);
+         tree decl = build_base_field_1 (t, binfo, next_field);
          DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
          DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
          SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
index 2b45d62ce21bf64d41f0c8104bad371097c7aeba..adc021b2a5c169a40f827470f4f37e96a201c6e7 100644 (file)
@@ -7302,6 +7302,7 @@ 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 structural_type_p                  (tree, bool = false);
 extern bool type_has_nontrivial_default_init   (const_tree);
 extern bool type_has_nontrivial_copy_init      (const_tree);
 extern void maybe_warn_parm_abi                        (tree, location_t);
index 061a92c9db09416adb247883f4be8a5369823cf6..8bacb3952ff22b37db0b8d33dd6163efe336551a 100644 (file)
@@ -25748,21 +25748,15 @@ invalid_nontype_parm_type_p (tree type, tsubst_flags_t complain)
        return false;
       if (!complete_type_or_else (type, NULL_TREE))
        return true;
-      if (!literal_type_p (type))
+      if (!structural_type_p (type))
        {
-         error ("%qT is not a valid type for a template non-type parameter "
-                "because it is not literal", type);
-         explain_non_literal_class (type);
-         return true;
-       }
-      if (cp_has_mutable_p (type))
-       {
-         error ("%qT is not a valid type for a template non-type parameter "
-                "because it has a mutable member", type);
+         auto_diagnostic_group d;
+         if (complain & tf_error)
+           error ("%qT is not a valid type for a template non-type parameter "
+                  "because it is not structural", type);
+         structural_type_p (type, true);
          return true;
        }
-      /* FIXME check op<=> and strong structural equality once spaceship is
-        implemented.  */
       return false;
     }
 
index 5cdeb6a07fef5226dc3e37b639a3f9abf2b9f8af..ba635d4ddbd9996f0da04d7856d5bd2b37944813 100644 (file)
@@ -4378,6 +4378,63 @@ zero_init_p (const_tree t)
   return 1;
 }
 
+/* True IFF T is a C++20 structural type (P1907R1) that can be used as a
+   non-type template parameter.  If EXPLAIN, explain why not.  */
+
+bool
+structural_type_p (tree t, bool explain)
+{
+  t = strip_array_types (t);
+  if (INTEGRAL_OR_ENUMERATION_TYPE_P (t))
+    return true;
+  if (NULLPTR_TYPE_P (t))
+    return true;
+  if (TYPE_PTR_P (t) || TYPE_PTRMEM_P (t))
+    return true;
+  if (TYPE_REF_P (t) && !TYPE_REF_IS_RVALUE (t))
+    return true;
+  if (!CLASS_TYPE_P (t))
+    return false;
+  if (TREE_CODE (t) == UNION_TYPE)
+    {
+      if (explain)
+       inform (location_of (t), "%qT is a union", t);
+      return false;
+    }
+  if (!literal_type_p (t))
+    {
+      if (explain)
+       explain_non_literal_class (t);
+      return false;
+    }
+  if (CLASSTYPE_HAS_MUTABLE (t))
+    {
+      if (explain)
+       inform (location_of (t), "%qT has a mutable member", t);
+      return false;
+    }
+  for (tree m = next_initializable_field (TYPE_FIELDS (t)); m;
+       m = next_initializable_field (DECL_CHAIN (m)))
+    {
+      if (TREE_PRIVATE (m) || TREE_PROTECTED (m))
+       {
+         if (explain)
+           inform (location_of (m), "%qD is not public", m);
+         return false;
+       }
+      if (!structural_type_p (TREE_TYPE (m)))
+       {
+         if (explain)
+           {
+             inform (location_of (m), "%qD has a non-structural type", m);
+             structural_type_p (TREE_TYPE (m), true);
+           }
+         return false;
+       }
+    }
+  return true;
+}
+
 /* Handle the C++17 [[nodiscard]] attribute, which is similar to the GNU
    warn_unused_result attribute.  */
 
index 2c00c5c6b881dcd64fe61ba9cba111d301740e3e..71ba8f981a0d0adb4abc6d8013f777d556842a08 100644 (file)
@@ -9,5 +9,5 @@ struct non_literal_class {
   // auto operator<=> (const non_literal_fixed_string&) = default;
 };
 
-template <non_literal_class> // { dg-error "11:is not a valid type for a template non-type parameter because it is not literal" }
+template <non_literal_class> // { dg-error "11:is not a valid type for a template non-type parameter because it is not structural" }
 int operator"" _udl();       // { dg-error "5:literal operator template .int operator\"\"_udl\\(\\). has invalid parameter list" }