https://gcc.gnu.org/g:5bdd45c4d910c83bb940e173c313aeed23bd183f

commit 5bdd45c4d910c83bb940e173c313aeed23bd183f
Author: Mikael Morin <mik...@gcc.gnu.org>
Date:   Sun Feb 16 22:25:01 2025 +0100

    fortran: Declare virtual tables read-only
    
    Add the read-only flag on the artificial variables we create to hold
    virtual tables.
    
            PR fortran/118896
    
    gcc/fortran/ChangeLog:
    
            * trans-decl.cc (gfc_get_symbol_decl): Set the read-only flag
            on virtual table declarations.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/class_79.f90: New test.

Diff:
---
 gcc/fortran/trans-decl.cc              |  2 +-
 gcc/testsuite/gfortran.dg/class_79.f90 | 57 ++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 0acf0e9adb78..cce1ae96046b 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -2105,7 +2105,7 @@ gfc_get_symbol_decl (gfc_symbol * sym)
   if (sym->attr.vtab || def_init)
     {
       DECL_ARTIFICIAL (decl) = 1;
-      if (def_init && sym->value)
+      if (sym->attr.vtab || sym->value)
        TREE_READONLY (decl) = 1;
     }
 
diff --git a/gcc/testsuite/gfortran.dg/class_79.f90 
b/gcc/testsuite/gfortran.dg/class_79.f90
new file mode 100644
index 000000000000..393a5cf1c37c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_79.f90
@@ -0,0 +1,57 @@
+! { dg-do compile }
+!
+! PR fortran/118896
+! Check that optimizations devirtualize all the calls to the internal _copy
+! typebound subroutine, and no reference to the virtual table remains.
+!
+! { dg-additional-options {-O2 -fdump-tree-original -fdump-tree-optimized} }
+! { dg-final { scan-tree-dump {__vtab} {original} } }
+! { dg-final { scan-tree-dump-not {__vtab} {optimized} } }
+
+module m
+  implicit none
+  type :: t1
+    integer :: i
+  end type
+end module m
+
+subroutine test_t1
+  use m
+  implicit none
+
+  class(t1), dimension(:), allocatable :: x, y
+
+  x = [t1(3), t1(2), t1(1)]
+
+  x = realloc_t1 (x)
+  if (.not.check_t1 (x, [2,3,1], 1) ) stop 3
+
+contains
+
+  function realloc_t1 (arg) result (res)
+    class(t1), dimension(:), allocatable :: arg
+    class(t1), dimension(:), allocatable :: res
+    select type (arg)
+      type is (t1)
+        allocate (res, source = [t1 (arg(2)%i), t1 (arg(1)%i), t1 (arg(3)%i)])
+    end select
+  end function realloc_t1
+
+  logical function check_t1 (arg, array, t, array2)
+    class(t1) :: arg(:)
+    integer :: array (:), t
+    integer, optional :: array2(:)
+    check_t1 = .true.
+    select type (arg)
+    type is (t1)
+      if (any (arg%i .ne. array)) check_t1 = .false.
+      if (t .eq. 2) check_t1 = .false.
+    class default
+      check_t1 = .false.
+    end select
+  end function check_t1
+
+end subroutine test_t1
+
+  call test_t1
+end

Reply via email to