https://gcc.gnu.org/g:41dee7da08873721a719849d19ef07c027e76dfb

commit r15-9749-g41dee7da08873721a719849d19ef07c027e76dfb
Author: Jerry DeLisle <jvdeli...@gcc.gnu.org>
Date:   Mon May 19 19:41:16 2025 -0700

    Fortran: Fix c_associated argument checks.
    
            PR fortran/120049
    
    gcc/fortran/ChangeLog:
    
            * check.cc (gfc_check_c_associated): Use new helper functions.
            Only call check_c_ptr_1 if optional c_ptr_2 tests succeed.
            (check_c_ptr_1): Handle only c_ptr_1 checks.
            (check_c_ptr_2): Expand checks for c_ptr_2 and handle cases
            where there is no derived pointer in the gfc_expr and check
            the inmod_sym_id only if it exists. Rephrase error message.
            * misc.cc (gfc_typename): Handle the case for BT_VOID rather
            than throw an internal error.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/pr120049_a.f90: Update test directives.
            * gfortran.dg/pr120049_b.f90: Update test directives
            * gfortran.dg/pr120049_2.f90: New test.
            * gfortran.dg/c_f_pointer_tests_6.f90: Adjust dg-error
            directive.
    
            Co-Authored-By: Steve Kargl <ka...@gcc.gnu.org>
    
    (cherry picked from commit 42983ffde6612b7f8a4e7ab3e76fa8b0d136e854)

Diff:
---
 gcc/fortran/check.cc                              | 125 ++++++++++++++++------
 gcc/fortran/misc.cc                               |   3 +
 gcc/testsuite/gfortran.dg/c_f_pointer_tests_6.f90 |   2 +-
 gcc/testsuite/gfortran.dg/pr120049_2.f90          |  62 +++++++++++
 gcc/testsuite/gfortran.dg/pr120049_a.f90          |   7 +-
 gcc/testsuite/gfortran.dg/pr120049_b.f90          |   2 -
 6 files changed, 164 insertions(+), 37 deletions(-)

diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 0073cd0b7802..ce9da31ceb32 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -5916,49 +5916,110 @@ gfc_check_c_sizeof (gfc_expr *arg)
 }
 
 
-bool
-gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
+/* Helper functions check_c_ptr_1 and check_c_ptr_2
+   used in gfc_check_c_associated.  */
+
+static inline
+bool check_c_ptr_1 (gfc_expr *c_ptr_1)
 {
-  if (c_ptr_1)
-    {
-      if (c_ptr_1->expr_type == EXPR_FUNCTION && c_ptr_1->ts.type == BT_VOID)
-       return true;
+  if ((c_ptr_1->ts.type == BT_VOID)
+      && (c_ptr_1->expr_type == EXPR_FUNCTION))
+    return true;
 
-      if (c_ptr_1->ts.type != BT_DERIVED
-         || c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
-         || (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
-             && c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
-       {
-         gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
-                    "type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
-         return false;
-       }
-    }
+  if (c_ptr_1->ts.type != BT_DERIVED
+      || c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
+      || (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
+         && c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
+       goto check_1_error;
 
-  if (!scalar_check (c_ptr_1, 0))
+  if ((c_ptr_1->ts.type == BT_DERIVED)
+       && (c_ptr_1->expr_type == EXPR_STRUCTURE)
+       && (c_ptr_1->ts.u.derived->intmod_sym_id
+          == ISOCBINDING_NULL_FUNPTR))
+    goto check_1_error;
+
+  if (scalar_check (c_ptr_1, 0))
+    return true;
+  else
+    /*  Return since the check_1_error message may not apply here. */
     return false;
 
-  if (c_ptr_2)
-    {
-      if (c_ptr_2->expr_type == EXPR_FUNCTION && c_ptr_2->ts.type == BT_VOID)
-       return true;
+check_1_error:
 
-      if (c_ptr_2->ts.type != BT_DERIVED
-         || c_ptr_2->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
-         || (c_ptr_1->ts.u.derived->intmod_sym_id
-             != c_ptr_2->ts.u.derived->intmod_sym_id))
+  gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
+            "type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
+  return false;
+}
+
+static inline
+bool check_c_ptr_2 (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
+{
+  switch (c_ptr_2->ts.type)
+  {
+    case BT_VOID:
+      if (c_ptr_2->expr_type == EXPR_FUNCTION)
        {
-         gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
-                  "same type as C_PTR_1: %s instead of %s", &c_ptr_1->where,
-                  gfc_typename (&c_ptr_1->ts), gfc_typename (&c_ptr_2->ts));
-         return false;
+         if ((c_ptr_1->ts.type == BT_DERIVED)
+              && c_ptr_1->expr_type == EXPR_STRUCTURE
+              && (c_ptr_1->ts.u.derived->intmod_sym_id
+                 == ISOCBINDING_FUNPTR))
+           goto check_2_error;
        }
-    }
+      break;
+
+    case BT_DERIVED:
+      if ((c_ptr_2->expr_type == EXPR_STRUCTURE)
+          && (c_ptr_2->ts.u.derived->intmod_sym_id == ISOCBINDING_PTR)
+          && (c_ptr_1->ts.type == BT_VOID)
+          && (c_ptr_1->expr_type == EXPR_FUNCTION))
+       return scalar_check (c_ptr_2, 1);
+
+      if ((c_ptr_2->expr_type == EXPR_STRUCTURE)
+          && (c_ptr_1->ts.type == BT_VOID)
+          && (c_ptr_1->expr_type == EXPR_FUNCTION))
+       goto check_2_error;
 
-  if (c_ptr_2 && !scalar_check (c_ptr_2, 1))
+      if (c_ptr_2->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING)
+       goto check_2_error;
+
+      if (c_ptr_1->ts.type == BT_DERIVED
+         && (c_ptr_1->ts.u.derived->intmod_sym_id
+             != c_ptr_2->ts.u.derived->intmod_sym_id))
+       goto check_2_error;
+      break;
+
+    default:
+      goto check_2_error;
+  }
+
+  if (scalar_check (c_ptr_2, 1))
+    return true;
+  else
+    /*  Return since the check_2_error message may not apply here. */
     return false;
 
-  return true;
+check_2_error:
+
+  gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
+            "same type as C_PTR_1, found %s instead of %s", &c_ptr_2->where,
+            gfc_typename (&c_ptr_2->ts), gfc_typename (&c_ptr_1->ts));
+
+  return false;
+ }
+
+
+bool
+gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
+{
+  if (c_ptr_2)
+    {
+      if (check_c_ptr_2 (c_ptr_1, c_ptr_2))
+       return check_c_ptr_1 (c_ptr_1);
+      else
+       return false;
+    }
+  else
+    return check_c_ptr_1 (c_ptr_1);
 }
 
 
diff --git a/gcc/fortran/misc.cc b/gcc/fortran/misc.cc
index 893c40fbba2c..b8bdf7578de6 100644
--- a/gcc/fortran/misc.cc
+++ b/gcc/fortran/misc.cc
@@ -214,6 +214,9 @@ gfc_typename (gfc_typespec *ts, bool for_hash)
     case BT_UNKNOWN:
       strcpy (buffer, "UNKNOWN");
       break;
+    case BT_VOID:
+      strcpy (buffer, "VOID");
+      break;
     default:
       gfc_internal_error ("gfc_typename(): Undefined type");
     }
diff --git a/gcc/testsuite/gfortran.dg/c_f_pointer_tests_6.f90 
b/gcc/testsuite/gfortran.dg/c_f_pointer_tests_6.f90
index 23ca88b0de05..bc2206d4e742 100644
--- a/gcc/testsuite/gfortran.dg/c_f_pointer_tests_6.f90
+++ b/gcc/testsuite/gfortran.dg/c_f_pointer_tests_6.f90
@@ -38,6 +38,6 @@ contains
     type(my_c_ptr_0) :: my_ptr2
     type(c_funptr) :: myfun
     print *,c_associated(my_ptr,my_ptr2)
-    print *,c_associated(my_ptr,myfun) ! { dg-error "Argument C_PTR_2 at .1. 
to C_ASSOCIATED shall have the same type as C_PTR_1: TYPE.c_ptr. instead of 
TYPE.c_funptr." }
+    print *,c_associated(my_ptr,myfun) ! { dg-error "Argument C_PTR_2 at .1. 
to C_ASSOCIATED shall have the same type as C_PTR_1, found TYPE.c_funptr. 
instead of TYPE.c_ptr." }
   end subroutine
 end
diff --git a/gcc/testsuite/gfortran.dg/pr120049_2.f90 
b/gcc/testsuite/gfortran.dg/pr120049_2.f90
new file mode 100644
index 000000000000..1f91e06e98ee
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr120049_2.f90
@@ -0,0 +1,62 @@
+! Compiled with pr120049_b.f90
+! { dg-options -O0 }
+! { dg-do compile }
+! { dg-compile-aux-modules "pr120049_b.f90" }
+!
+! Test the fix for PR120049
+program tests_gtk_sup
+  use gtk_sup
+  implicit none
+  
+  type mytype
+    integer :: myint
+  end type mytype
+  type(mytype) :: ijkl = mytype(42)
+  logical :: truth
+  real :: var1
+  type(c_ptr), target :: val
+  type(c_funptr), target :: fptr
+  character(15) :: stringy
+  complex :: certainly
+  truth = .true.
+  var1 = 86.
+  stringy = "what the hay!"
+  certainly = (3.14,-4.13)
+  if (c_associated(val, c_loc(val))) then
+    stop 1
+  endif
+  if (c_associated(c_loc(val), val)) then
+    stop 2
+  endif
+  print *, c_associated(fptr, C_NULL_FUNPTR)
+  print *, c_associated(c_loc(val), C_NULL_PTR)
+  print *, c_associated(C_NULL_PTR, c_loc(val)) 
+  print *, c_associated(c_loc(val), 42) ! { dg-error "C_ASSOCIATED shall have 
the" }
+  print *, c_associated(c_loc(val), .42) ! { dg-error "C_ASSOCIATED shall have 
the" }
+  print *, c_associated(c_loc(val), truth) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(c_loc(val), .false.) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(c_loc(val), var1) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(c_loc(val), stringy) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(c_loc(val), certainly) ! { dg-error "C_ASSOCIATED 
shall have the" }
+  print *, c_associated(42) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(.42) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(truth) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(.false.) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(var1) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(stringy) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(certainly) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(.42) ! { dg-error "C_ASSOCIATED shall have the" }
+  print *, c_associated(val, testit(val)) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(testit(val), val) ! { dg-error "C_ASSOCIATED shall 
have the" }
+  print *, c_associated(testit(val)) ! { dg-error "C_ASSOCIATED shall have 
the" }
+  print *, c_associated(c_loc(val), C_NULL_FUNPTR) ! { dg-error "C_ASSOCIATED 
shall have the" }
+  print *, c_associated(C_NULL_FUNPTR, c_loc(val)) ! { dg-error "C_ASSOCIATED 
shall have the" }
+contains
+
+  function testit (avalue) result(res)
+    type(c_ptr) :: avalue
+    type(mytype) :: res
+    res%myint = 42
+  end function
+
+end program tests_gtk_sup
diff --git a/gcc/testsuite/gfortran.dg/pr120049_a.f90 
b/gcc/testsuite/gfortran.dg/pr120049_a.f90
index c404a4dedd9a..7095314fe0e6 100644
--- a/gcc/testsuite/gfortran.dg/pr120049_a.f90
+++ b/gcc/testsuite/gfortran.dg/pr120049_a.f90
@@ -1,5 +1,8 @@
-! { dg-do preprocess }
-! { dg-additional-options "-cpp" }
+! Compiled with pr120049_b.f90
+! { dg-options -O0 }
+! { dg-do run }
+! { dg-compile-aux-modules "pr120049_b.f90" }
+! { dg-additional-sources pr120049_b.f90 }
 !
 ! Test the fix for PR86248
 program tests_gtk_sup
diff --git a/gcc/testsuite/gfortran.dg/pr120049_b.f90 
b/gcc/testsuite/gfortran.dg/pr120049_b.f90
index 127db984077d..28a2783abbd9 100644
--- a/gcc/testsuite/gfortran.dg/pr120049_b.f90
+++ b/gcc/testsuite/gfortran.dg/pr120049_b.f90
@@ -1,5 +1,3 @@
-! { dg-do  run }
-! { dg-additional-sources pr120049_a.f90 }
 !
 ! Module for pr120049.f90
 !

Reply via email to