[gcc r15-1704] Add gfc_class_set_vptr.

Andre Vehreschild vehre@gcc.gnu.org
Fri Jun 28 09:09:39 GMT 2024


https://gcc.gnu.org/g:aa3599a10cab34104c0b9bd6951c5f0c420795d8

commit r15-1704-gaa3599a10cab34104c0b9bd6951c5f0c420795d8
Author: Andre Vehreschild <vehre@gcc.gnu.org>
Date:   Tue Jun 11 12:52:26 2024 +0200

    Add gfc_class_set_vptr.
    
    First step to adding a general assign all class type's data members
    routine.  Having a general routine prevents forgetting to tackle the
    edge cases, e.g. setting _len.
    
    gcc/fortran/ChangeLog:
    
            * trans-expr.cc (gfc_class_set_vptr): Add setting of _vptr
            member.
            * trans-intrinsic.cc (conv_intrinsic_move_alloc): First use
            of gfc_class_set_vptr and refactor very similar code.
            * trans.h (gfc_class_set_vptr): Declare the new function.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/unlimited_polymorphic_11.f90: Remove unnecessary
            casts in gd-final expression.

Diff:
---
 gcc/fortran/trans-expr.cc                          |  48 +++++
 gcc/fortran/trans-intrinsic.cc                     | 203 ++++++---------------
 gcc/fortran/trans.h                                |   6 +-
 .../gfortran.dg/unlimited_polymorphic_11.f90       |   2 +-
 4 files changed, 111 insertions(+), 148 deletions(-)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 454b87581f5..477c2720187 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -599,6 +599,54 @@ gfc_reset_vptr (stmtblock_t *block, gfc_expr *e, tree class_container,
 }
 
 
+/* Set the vptr of a class in to from the type given in from.  If from is NULL,
+   then reset the vptr to the default or to.  */
+
+void
+gfc_class_set_vptr (stmtblock_t *block, tree to, tree from)
+{
+  tree tmp, vptr_ref;
+
+  vptr_ref = gfc_get_vptr_from_expr (to);
+  if (POINTER_TYPE_P (TREE_TYPE (from))
+      && GFC_CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (from))))
+    {
+      gfc_add_modify (block, vptr_ref,
+		      fold_convert (TREE_TYPE (vptr_ref),
+				    gfc_get_vptr_from_expr (from)));
+    }
+  else if (VAR_P (from)
+	   && strncmp (IDENTIFIER_POINTER (DECL_NAME (from)), "__vtab", 6) == 0)
+    {
+      gfc_add_modify (block, vptr_ref,
+		      gfc_build_addr_expr (TREE_TYPE (vptr_ref), from));
+    }
+  else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (from)))
+	   && GFC_CLASS_TYPE_P (
+	     TREE_TYPE (TREE_OPERAND (TREE_OPERAND (from, 0), 0))))
+    {
+      gfc_add_modify (block, vptr_ref,
+		      fold_convert (TREE_TYPE (vptr_ref),
+				    gfc_get_vptr_from_expr (TREE_OPERAND (
+				      TREE_OPERAND (from, 0), 0))));
+    }
+  else
+    {
+      tree vtab;
+      gfc_symbol *type;
+      tmp = TREE_TYPE (from);
+      if (POINTER_TYPE_P (tmp))
+	tmp = TREE_TYPE (tmp);
+      gfc_find_symbol (IDENTIFIER_POINTER (TYPE_NAME (tmp)), gfc_current_ns, 1,
+		       &type);
+      vtab = gfc_find_derived_vtab (type)->backend_decl;
+      gcc_assert (vtab);
+      gfc_add_modify (block, vptr_ref,
+		      gfc_build_addr_expr (TREE_TYPE (vptr_ref), vtab));
+    }
+}
+
+
 /* Reset the len for unlimited polymorphic objects.  */
 
 void
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index ac7fcd250d3..5ea10e84060 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -12667,10 +12667,9 @@ conv_intrinsic_move_alloc (gfc_code *code)
 {
   stmtblock_t block;
   gfc_expr *from_expr, *to_expr;
-  gfc_expr *to_expr2, *from_expr2 = NULL;
   gfc_se from_se, to_se;
-  tree tmp;
-  bool coarray;
+  tree tmp, to_tree, from_tree;
+  bool coarray, from_is_class, from_is_scalar;
 
   gfc_start_block (&block);
 
@@ -12680,178 +12679,94 @@ conv_intrinsic_move_alloc (gfc_code *code)
   gfc_init_se (&from_se, NULL);
   gfc_init_se (&to_se, NULL);
 
-  gcc_assert (from_expr->ts.type != BT_CLASS
-	      || to_expr->ts.type == BT_CLASS);
+  gcc_assert (from_expr->ts.type != BT_CLASS || to_expr->ts.type == BT_CLASS);
   coarray = gfc_get_corank (from_expr) != 0;
 
-  if (from_expr->rank == 0 && !coarray)
+  from_is_class = from_expr->ts.type == BT_CLASS;
+  from_is_scalar = from_expr->rank == 0 && !coarray;
+  if (to_expr->ts.type == BT_CLASS || from_is_scalar)
     {
-      if (from_expr->ts.type != BT_CLASS)
-	from_expr2 = from_expr;
+      from_se.want_pointer = 1;
+      if (from_is_scalar)
+	gfc_conv_expr (&from_se, from_expr);
       else
-	{
-	  from_expr2 = gfc_copy_expr (from_expr);
-	  gfc_add_data_component (from_expr2);
-	}
-
-      if (to_expr->ts.type != BT_CLASS)
-	to_expr2 = to_expr;
+	gfc_conv_expr_descriptor (&from_se, from_expr);
+      if (from_is_class)
+	from_tree = gfc_class_data_get (from_se.expr);
       else
 	{
-	  to_expr2 = gfc_copy_expr (to_expr);
-	  gfc_add_data_component (to_expr2);
+	  gfc_symbol *vtab;
+	  from_tree = from_se.expr;
+
+	  vtab = gfc_find_vtab (&from_expr->ts);
+	  gcc_assert (vtab);
+	  from_se.expr = gfc_get_symbol_decl (vtab);
 	}
+      gfc_add_block_to_block (&block, &from_se.pre);
 
-      from_se.want_pointer = 1;
       to_se.want_pointer = 1;
-      gfc_conv_expr (&from_se, from_expr2);
-      gfc_conv_expr (&to_se, to_expr2);
-      gfc_add_block_to_block (&block, &from_se.pre);
+      if (to_expr->rank == 0)
+	gfc_conv_expr (&to_se, to_expr);
+      else
+	gfc_conv_expr_descriptor (&to_se, to_expr);
+      if (to_expr->ts.type == BT_CLASS)
+	to_tree = gfc_class_data_get (to_se.expr);
+      else
+	to_tree = to_se.expr;
       gfc_add_block_to_block (&block, &to_se.pre);
 
       /* Deallocate "to".  */
-      tmp = gfc_deallocate_scalar_with_status (to_se.expr, NULL_TREE, NULL_TREE,
-					       true, to_expr, to_expr->ts);
-      gfc_add_expr_to_block (&block, tmp);
+      if (to_expr->rank == 0)
+	{
+	  tmp
+	    = gfc_deallocate_scalar_with_status (to_tree, NULL_TREE, NULL_TREE,
+						 true, to_expr, to_expr->ts);
+	  gfc_add_expr_to_block (&block, tmp);
+	}
 
-      /* Assign (_data) pointers.  */
-      gfc_add_modify_loc (input_location, &block, to_se.expr,
-			  fold_convert (TREE_TYPE (to_se.expr), from_se.expr));
+      if (from_is_scalar)
+	{
+	  /* Assign (_data) pointers.  */
+	  gfc_add_modify_loc (input_location, &block, to_tree,
+			      fold_convert (TREE_TYPE (to_tree), from_tree));
 
-      /* Set "from" to NULL.  */
-      gfc_add_modify_loc (input_location, &block, from_se.expr,
-			  fold_convert (TREE_TYPE (from_se.expr), null_pointer_node));
+	  /* Set "from" to NULL.  */
+	  gfc_add_modify_loc (input_location, &block, from_tree,
+			      fold_convert (TREE_TYPE (from_tree),
+					    null_pointer_node));
 
-      gfc_add_block_to_block (&block, &from_se.post);
+	  gfc_add_block_to_block (&block, &from_se.post);
+	}
       gfc_add_block_to_block (&block, &to_se.post);
 
       /* Set _vptr.  */
       if (to_expr->ts.type == BT_CLASS)
 	{
-	  gfc_symbol *vtab;
-
-	  gfc_free_expr (to_expr2);
-	  gfc_init_se (&to_se, NULL);
-	  to_se.want_pointer = 1;
-	  gfc_add_vptr_component (to_expr);
-	  gfc_conv_expr (&to_se, to_expr);
-
-	  if (from_expr->ts.type == BT_CLASS)
-	    {
-	      if (UNLIMITED_POLY (from_expr))
-		vtab = NULL;
-	      else
-		{
-		  vtab = gfc_find_derived_vtab (from_expr->ts.u.derived);
-		  gcc_assert (vtab);
-		}
-
-	      gfc_free_expr (from_expr2);
-	      gfc_init_se (&from_se, NULL);
-	      from_se.want_pointer = 1;
-	      gfc_add_vptr_component (from_expr);
-	      gfc_conv_expr (&from_se, from_expr);
-	      gfc_add_modify_loc (input_location, &block, to_se.expr,
-				  fold_convert (TREE_TYPE (to_se.expr),
-				  from_se.expr));
-
-              /* Reset _vptr component to declared type.  */
-	      if (vtab == NULL)
-		/* Unlimited polymorphic.  */
-		gfc_add_modify_loc (input_location, &block, from_se.expr,
-				    fold_convert (TREE_TYPE (from_se.expr),
-						  null_pointer_node));
-	      else
-		{
-		  tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
-		  gfc_add_modify_loc (input_location, &block, from_se.expr,
-				      fold_convert (TREE_TYPE (from_se.expr), tmp));
-		}
-	    }
-	  else
-	    {
-	      vtab = gfc_find_vtab (&from_expr->ts);
-	      gcc_assert (vtab);
-	      tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
-	      gfc_add_modify_loc (input_location, &block, to_se.expr,
-				  fold_convert (TREE_TYPE (to_se.expr), tmp));
-	    }
-	}
-
-      if (to_expr->ts.type == BT_CHARACTER && to_expr->ts.deferred)
-	{
-	  gfc_add_modify_loc (input_location, &block, to_se.string_length,
-			      fold_convert (TREE_TYPE (to_se.string_length),
-					    from_se.string_length));
-	  if (from_expr->ts.deferred)
-	    gfc_add_modify_loc (input_location, &block, from_se.string_length,
-			build_int_cst (TREE_TYPE (from_se.string_length), 0));
+	  gfc_class_set_vptr (&block, to_se.expr, from_se.expr);
+	  if (from_is_class)
+	    gfc_reset_vptr (&block, from_expr);
 	}
 
-      return gfc_finish_block (&block);
-    }
-
-  /* Update _vptr component.  */
-  if (to_expr->ts.type == BT_CLASS)
-    {
-      gfc_symbol *vtab;
-
-      to_se.want_pointer = 1;
-      to_expr2 = gfc_copy_expr (to_expr);
-      gfc_add_vptr_component (to_expr2);
-      gfc_conv_expr (&to_se, to_expr2);
-
-      if (from_expr->ts.type == BT_CLASS)
+      if (from_is_scalar)
 	{
-	  if (UNLIMITED_POLY (from_expr))
-	    vtab = NULL;
-	  else
+	  if (to_expr->ts.type == BT_CHARACTER && to_expr->ts.deferred)
 	    {
-	      vtab = gfc_find_derived_vtab (from_expr->ts.u.derived);
-	      gcc_assert (vtab);
+	      gfc_add_modify_loc (input_location, &block, to_se.string_length,
+				  fold_convert (TREE_TYPE (to_se.string_length),
+						from_se.string_length));
+	      if (from_expr->ts.deferred)
+		gfc_add_modify_loc (
+		  input_location, &block, from_se.string_length,
+		  build_int_cst (TREE_TYPE (from_se.string_length), 0));
 	    }
 
-	  from_se.want_pointer = 1;
-	  from_expr2 = gfc_copy_expr (from_expr);
-	  gfc_add_vptr_component (from_expr2);
-	  gfc_conv_expr (&from_se, from_expr2);
-	  gfc_add_modify_loc (input_location, &block, to_se.expr,
-			      fold_convert (TREE_TYPE (to_se.expr),
-			      from_se.expr));
-
-	  /* Reset _vptr component to declared type.  */
-	  if (vtab == NULL)
-	    /* Unlimited polymorphic.  */
-	    gfc_add_modify_loc (input_location, &block, from_se.expr,
-				fold_convert (TREE_TYPE (from_se.expr),
-					      null_pointer_node));
-	  else
-	    {
-	      tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
-	      gfc_add_modify_loc (input_location, &block, from_se.expr,
-				  fold_convert (TREE_TYPE (from_se.expr), tmp));
-	    }
-	}
-      else
-	{
-	  vtab = gfc_find_vtab (&from_expr->ts);
-	  gcc_assert (vtab);
-	  tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
-	  gfc_add_modify_loc (input_location, &block, to_se.expr,
-			      fold_convert (TREE_TYPE (to_se.expr), tmp));
+	  return gfc_finish_block (&block);
 	}
 
-      gfc_free_expr (to_expr2);
       gfc_init_se (&to_se, NULL);
-
-      if (from_expr->ts.type == BT_CLASS)
-	{
-	  gfc_free_expr (from_expr2);
-	  gfc_init_se (&from_se, NULL);
-	}
+      gfc_init_se (&from_se, NULL);
     }
 
-
   /* Deallocate "to".  */
   if (from_expr->rank == 0)
     {
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index f019c89edf2..ec04aede0fd 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -451,9 +451,9 @@ tree gfc_vptr_def_init_get (tree);
 tree gfc_vptr_copy_get (tree);
 tree gfc_vptr_final_get (tree);
 tree gfc_vptr_deallocate_get (tree);
-void
-gfc_reset_vptr (stmtblock_t *, gfc_expr *, tree = NULL_TREE,
-		gfc_symbol * = nullptr);
+void gfc_reset_vptr (stmtblock_t *, gfc_expr *, tree = NULL_TREE,
+		     gfc_symbol * = nullptr);
+void gfc_class_set_vptr (stmtblock_t *, tree, tree);
 void gfc_reset_len (stmtblock_t *, gfc_expr *);
 tree gfc_get_class_from_gfc_expr (gfc_expr *);
 tree gfc_get_class_from_expr (tree);
diff --git a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_11.f90 b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_11.f90
index bbd3d067f3f..653992f40eb 100644
--- a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_11.f90
+++ b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_11.f90
@@ -10,4 +10,4 @@
   call move_alloc(a,c)
 end
 
-! { dg-final { scan-tree-dump "\\(struct __vtype__STAR \\*\\) c._vptr = \\(struct __vtype__STAR \\*\\) a._vptr;" "original" } }
+! { dg-final { scan-tree-dump "c._vptr = a._vptr;" "original" } }


More information about the Gcc-cvs mailing list