Fix C++20 structural type vs. private base.
authorJason Merrill <jason@redhat.com>
Tue, 10 Dec 2019 20:10:59 +0000 (15:10 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 10 Dec 2019 20:10:59 +0000 (15:10 -0500)
In my patch to implement C++20 "structural type" I tried to set the access
flags on the artificial base fields appropriately, but failed.  I was
copying TREE_PRIVATE from the binfo, but TREE_PRIVATE on binfo is just a
temporary cache for dfs_access_in_type; we really need to get the
inheritance access information from BINFO_BASE_ACCESSES.

* class.c (build_base_field_1): Take access parameter.
(build_base_field): Likewise.
(build_base_fields, layout_virtual_bases): Pass it.
* tree.c (structural_type_p): Improve private base diagnostic.

From-SVN: r279184

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/tree.c
gcc/testsuite/g++.dg/cpp2a/nontype-class25.C [new file with mode: 0644]

index b640e15ec2924a1ec38166ff4a286e7787989d2d..6b15fc306e29926d97bcf9a2fe50a558f4da2811 100644 (file)
@@ -1,5 +1,11 @@
 2019-12-10  Jason Merrill  <jason@redhat.com>
 
+       Fix C++20 structural type vs. private base.
+       * class.c (build_base_field_1): Take access parameter.
+       (build_base_field): Likewise.
+       (build_base_fields, layout_virtual_bases): Pass it.
+       * tree.c (structural_type_p): Improve private base diagnostic.
+
        PR c++/92560 - ICE with decltype and rewritten operator.
        * call.c (build_new_op_1): Clear tf_decltype on inner call.
 
index d8bb44990b7c1565528014a79951d15834c072d6..a8c6b1cb01c78fb707488505a4d1dad6f9edf87b 100644 (file)
@@ -134,7 +134,6 @@ static void build_vtbl_initializer (tree, tree, tree, tree, int *,
 static bool check_bitfield_decl (tree);
 static bool check_field_decl (tree, tree, int *, int *);
 static void check_field_decls (tree, tree *, int *, int *);
-static tree *build_base_field (record_layout_info, tree, splay_tree, tree *);
 static void build_base_fields (record_layout_info, splay_tree, tree *);
 static void check_methods (tree);
 static void remove_zero_width_bit_fields (tree);
@@ -4407,7 +4406,7 @@ 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 binfo, tree *&next_field)
+build_base_field_1 (tree t, tree binfo, tree access, tree *&next_field)
 {
   /* Create the FIELD_DECL.  */
   tree basetype = BINFO_TYPE (binfo);
@@ -4417,8 +4416,6 @@ build_base_field_1 (tree t, tree binfo, tree *&next_field)
   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;
@@ -4432,6 +4429,11 @@ build_base_field_1 (tree t, tree binfo, tree *&next_field)
   SET_DECL_MODE (decl, TYPE_MODE (basetype));
   DECL_FIELD_IS_BASE (decl) = 1;
 
+  if (access == access_private_node)
+    TREE_PRIVATE (decl) = true;
+  else if (access == access_protected_node)
+    TREE_PROTECTED (decl) = true;
+
   /* Add the new FIELD_DECL to the list of fields for T.  */
   DECL_CHAIN (decl) = *next_field;
   *next_field = decl;
@@ -4450,7 +4452,7 @@ build_base_field_1 (tree t, tree binfo, tree *&next_field)
    Returns the location at which the next field should be inserted.  */
 
 static tree *
-build_base_field (record_layout_info rli, tree binfo,
+build_base_field (record_layout_info rli, tree binfo, tree access,
                  splay_tree offsets, tree *next_field)
 {
   tree t = rli->t;
@@ -4471,7 +4473,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, binfo, next_field);
+      decl = build_base_field_1 (t, binfo, access, 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
@@ -4505,7 +4507,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, binfo, next_field);
+         tree decl = build_base_field_1 (t, binfo, access, 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);
@@ -4536,25 +4538,39 @@ build_base_fields (record_layout_info rli,
   /* Chain to hold all the new FIELD_DECLs which stand in for base class
      subobjects.  */
   tree t = rli->t;
-  int n_baseclasses = BINFO_N_BASE_BINFOS (TYPE_BINFO (t));
-  int i;
+  tree binfo = TYPE_BINFO (t);
+  int n_baseclasses = BINFO_N_BASE_BINFOS (binfo);
 
   /* The primary base class is always allocated first.  */
-  if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
-    next_field = build_base_field (rli, CLASSTYPE_PRIMARY_BINFO (t),
-                                  offsets, next_field);
+  const tree primary_binfo = CLASSTYPE_PRIMARY_BINFO (t);
+  if (primary_binfo)
+    {
+      /* We need to walk BINFO_BASE_BINFO to find the access of the primary
+        base, if it is direct.  Indirect base fields are private.  */
+      tree primary_access = access_private_node;
+      for (int i = 0; i < n_baseclasses; ++i)
+       {
+         tree base_binfo = BINFO_BASE_BINFO (binfo, i);
+         if (base_binfo == primary_binfo)
+           {
+             primary_access = BINFO_BASE_ACCESS (binfo, i);
+             break;
+           }
+       }
+      next_field = build_base_field (rli, primary_binfo,
+                                    primary_access,
+                                    offsets, next_field);
+    }
 
   /* Now allocate the rest of the bases.  */
-  for (i = 0; i < n_baseclasses; ++i)
+  for (int i = 0; i < n_baseclasses; ++i)
     {
-      tree base_binfo;
-
-      base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (t), i);
+      tree base_binfo = BINFO_BASE_BINFO (binfo, i);
 
       /* The primary base was already allocated above, so we don't
         need to allocate it again here.  */
-      if (base_binfo == CLASSTYPE_PRIMARY_BINFO (t))
-       continue;
+      if (base_binfo == primary_binfo)
+       continue;
 
       /* Virtual bases are added at the end (a primary virtual base
         will have already been added).  */
@@ -4562,6 +4578,7 @@ build_base_fields (record_layout_info rli,
        continue;
 
       next_field = build_base_field (rli, base_binfo,
+                                    BINFO_BASE_ACCESS (binfo, i),
                                     offsets, next_field);
     }
 }
@@ -6141,6 +6158,7 @@ layout_virtual_bases (record_layout_info rli, splay_tree offsets)
          /* This virtual base is not a primary base of any class in the
             hierarchy, so we have to add space for it.  */
          next_field = build_base_field (rli, vbase,
+                                        access_private_node,
                                         offsets, next_field);
        }
     }
index c7c063f6df7f782a053903ac4915bcee547d409d..7b5a3e423f9fd2b429a52c9c19bfc40a594eae6a 100644 (file)
@@ -4447,7 +4447,13 @@ structural_type_p (tree t, bool explain)
       if (TREE_PRIVATE (m) || TREE_PROTECTED (m))
        {
          if (explain)
-           inform (location_of (m), "%qD is not public", m);
+           {
+             if (DECL_FIELD_IS_BASE (m))
+               inform (location_of (m), "base class %qT is not public",
+                       TREE_TYPE (m));
+             else
+               inform (location_of (m), "%qD is not public", m);
+           }
          return false;
        }
       if (!structural_type_p (TREE_TYPE (m)))
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class25.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class25.C
new file mode 100644 (file)
index 0000000..67d6f09
--- /dev/null
@@ -0,0 +1,6 @@
+// { dg-do compile { target c++2a } }
+
+struct base { int i{}; };
+struct derived : private base {};
+template <derived> struct has_nttp_param{}; // { dg-error "non-type" }
+has_nttp_param<{}> v;