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

commit r16-423-ge7a2b8b76ae0c8f1e49c780aa82ebb5f0325f515
Author: Thomas Koenig <tkoe...@gcc.gnu.org>
Date:   Tue May 6 18:05:41 2025 +0200

    Fix PR 119928, formal arguments used to wrongly inferred for CLASS.
    
    The problem was indeed that generating a formal from an actual
    arglist is a bad idea when classes are involved.  Fixed in the
    attached patch.  I think it still makes sense to remove the checks
    when the other attributes are present (or PR96073 may come back
    in different guise, even if I have to test case at present).
    I have also converted the test to a run-time check.
    
    gcc/fortran/ChangeLog:
    
            PR fortran/119928
            * interface.cc (gfc_check_dummy_characteristics): Do not issue
            error if one dummy symbol has been generated from an actual
            argument and the other one has OPTIONAL, INTENT, ALLOCATABLE,
            POINTER, TARGET, VALUE, ASYNCHRONOUS or CONTIGUOUS.
            (gfc_get_formal_from_actual_arglist): Do nothing if symbol
            is a class.
    
    gcc/testsuite/ChangeLog:
    
            PR fortran/119928
            * gfortran.dg/interface_60.f90: New test.

Diff:
---
 gcc/fortran/interface.cc                   | 135 ++++++++++++++++-------------
 gcc/testsuite/gfortran.dg/interface_60.f90 |  70 +++++++++++++++
 2 files changed, 143 insertions(+), 62 deletions(-)

diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index 1e552a3df861..753f589ff677 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -1403,77 +1403,82 @@ gfc_check_dummy_characteristics (gfc_symbol *s1, 
gfc_symbol *s2,
        }
     }
 
-  /* Check INTENT.  */
-  if (s1->attr.intent != s2->attr.intent && !s1->attr.artificial
-      && !s2->attr.artificial)
-    {
-      snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+  /* A lot of information is missing for artificially generated
+     formal arguments, let's not look into that.  */
 
-  /* Check OPTIONAL attribute.  */
-  if (s1->attr.optional != s2->attr.optional)
+  if (!s1->attr.artificial && !s2->attr.artificial)
     {
-      snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check INTENT.  */
+      if (s1->attr.intent != s2->attr.intent)
+       {
+         snprintf (errmsg, err_len, "INTENT mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check ALLOCATABLE attribute.  */
-  if (s1->attr.allocatable != s2->attr.allocatable)
-    {
-      snprintf (errmsg, err_len, "ALLOCATABLE mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check OPTIONAL attribute.  */
+      if (s1->attr.optional != s2->attr.optional)
+       {
+         snprintf (errmsg, err_len, "OPTIONAL mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check POINTER attribute.  */
-  if (s1->attr.pointer != s2->attr.pointer)
-    {
-      snprintf (errmsg, err_len, "POINTER mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check ALLOCATABLE attribute.  */
+      if (s1->attr.allocatable != s2->attr.allocatable)
+       {
+         snprintf (errmsg, err_len, "ALLOCATABLE mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check TARGET attribute.  */
-  if (s1->attr.target != s2->attr.target)
-    {
-      snprintf (errmsg, err_len, "TARGET mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check POINTER attribute.  */
+      if (s1->attr.pointer != s2->attr.pointer)
+       {
+         snprintf (errmsg, err_len, "POINTER mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check ASYNCHRONOUS attribute.  */
-  if (s1->attr.asynchronous != s2->attr.asynchronous)
-    {
-      snprintf (errmsg, err_len, "ASYNCHRONOUS mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check TARGET attribute.  */
+      if (s1->attr.target != s2->attr.target)
+       {
+         snprintf (errmsg, err_len, "TARGET mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check CONTIGUOUS attribute.  */
-  if (s1->attr.contiguous != s2->attr.contiguous)
-    {
-      snprintf (errmsg, err_len, "CONTIGUOUS mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check ASYNCHRONOUS attribute.  */
+      if (s1->attr.asynchronous != s2->attr.asynchronous)
+       {
+         snprintf (errmsg, err_len, "ASYNCHRONOUS mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check VALUE attribute.  */
-  if (s1->attr.value != s2->attr.value)
-    {
-      snprintf (errmsg, err_len, "VALUE mismatch in argument '%s'",
-               s1->name);
-      return false;
-    }
+      /* Check CONTIGUOUS attribute.  */
+      if (s1->attr.contiguous != s2->attr.contiguous)
+       {
+         snprintf (errmsg, err_len, "CONTIGUOUS mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
 
-  /* Check VOLATILE attribute.  */
-  if (s1->attr.volatile_ != s2->attr.volatile_)
-    {
-      snprintf (errmsg, err_len, "VOLATILE mismatch in argument '%s'",
-               s1->name);
-      return false;
+      /* Check VALUE attribute.  */
+      if (s1->attr.value != s2->attr.value)
+       {
+         snprintf (errmsg, err_len, "VALUE mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
+
+      /* Check VOLATILE attribute.  */
+      if (s1->attr.volatile_ != s2->attr.volatile_)
+       {
+         snprintf (errmsg, err_len, "VOLATILE mismatch in argument '%s'",
+                   s1->name);
+         return false;
+       }
     }
 
   /* Check interface of dummy procedures.  */
@@ -5849,6 +5854,12 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym,
   char name[GFC_MAX_SYMBOL_LEN + 1];
   static int var_num;
 
+  /* Do not infer the formal from actual arguments if we are dealing with
+     classes.  */
+
+  if (sym->ts.type == BT_CLASS)
+    return;
+
   f = &sym->formal;
   for (a = actual_args; a != NULL; a = a->next)
     {
diff --git a/gcc/testsuite/gfortran.dg/interface_60.f90 
b/gcc/testsuite/gfortran.dg/interface_60.f90
new file mode 100644
index 000000000000..a7701f602d7a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/interface_60.f90
@@ -0,0 +1,70 @@
+! { dg-do run }
+! { dg-options "-Wexternal-argument-mismatch" }
+! Originally proc_ptr_52.f90, this gave an error with the warning above.
+
+module cs
+
+implicit none
+
+integer, target :: integer_target
+
+abstract interface
+   function classStar_map_ifc(x) result(y)
+      class(*), pointer            :: y
+      class(*), target, intent(in) :: x
+   end function classStar_map_ifc
+end interface
+
+contains
+
+   function fun(x) result(y)
+      class(*), pointer            :: y
+      class(*), target, intent(in) :: x
+      select type (x)
+      type is (integer)
+         integer_target = x        ! Deals with dangling target.
+         y => integer_target
+      class default
+         y => null()
+      end select
+   end function fun
+
+   function apply(fap, x) result(y)
+      procedure(classStar_map_ifc) :: fap
+      integer, intent(in) :: x
+      integer :: y
+      class(*), pointer :: p
+      y = 0                        ! Get rid of 'y' undefined warning
+      p => fap (x)
+      select type (p)
+      type is (integer)
+         y = p
+      end select
+   end function apply
+
+   function selector() result(fsel)
+      procedure(classStar_map_ifc), pointer :: fsel
+      fsel => fun
+   end function selector
+
+end module cs
+
+
+program classStar_map
+
+use cs
+implicit none
+
+integer :: x, y
+procedure(classStar_map_ifc), pointer :: fm
+
+x = 123654
+fm => selector ()               ! Fixed by second chunk in patch
+y = apply (fm, x)               ! Fixed by first chunk in patch
+if (x .ne. y) stop 1
+
+x = 2 * x
+y = apply (fun, x)             ! PR93925; fixed as above
+if (x .ne. y) stop 2
+
+end program classStar_map

Reply via email to