Hello world,

the attached patch handles dumping prototypes for C functions returning
function pointers.  For the test case

MODULE test
   USE, INTRINSIC :: ISO_C_BINDING
CONTAINS
   FUNCTION lookup(idx) BIND(C)
     type(C_FUNPTR) :: lookup
     integer(C_INT), VALUE :: idx
     lookup = C_FUNLOC(x1)
   END FUNCTION lookup

   subroutine x1()
   end subroutine x1
 END MODULE test

the prototype is

void (*lookup (int idx)) ();

Regression-tested.  Again no test case because I don't know
how.  During testing, I also found that vtabs were dumped,
this is also corrected.

OK for trunk?

Best regards

        Thomas

gcc/fortran/ChangeLog:

        PR fortran/119419
        * dump-parse-tree.cc (write_funptr_fcn): New function.
        (write_type): Invoke it for C_FUNPTR.
        (write_interop_decl): Do not dump vtabs.

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 1a15757b57b..837469c8aae 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -4038,6 +4038,7 @@ static void write_interop_decl (gfc_symbol *);
 static void write_proc (gfc_symbol *, bool);
 static void show_external_symbol (gfc_gsymbol *, void *);
 static void write_type (gfc_symbol *sym);
+static void write_funptr_fcn (gfc_symbol *);
 
 /* Do we need to write out an #include <ISO_Fortran_binding.h> or not?  */
 
@@ -4379,9 +4380,10 @@ write_type (gfc_symbol *sym)
 {
   gfc_component *c;
 
-  /* Don't dump our iso c module.  */
+  /* Don't dump our iso c module, nor vtypes.  */
 
-  if (sym->from_intmod == INTMOD_ISO_C_BINDING || sym->attr.flavor != FL_DERIVED)
+  if (sym->from_intmod == INTMOD_ISO_C_BINDING || sym->attr.flavor != FL_DERIVED
+      || sym->attr.vtype)
     return;
 
   fprintf (dumpfile, "typedef struct %s {\n", sym->name);
@@ -4495,6 +4497,18 @@ write_formal_arglist (gfc_symbol *sym, bool bind_c)
 
 }
 
+/* Write out an interoperable function returning a function pointer.  Better
+   handled separately.  As we know nothing about the type, assume
+   a C default return of int.  */
+
+static void
+write_funptr_fcn (gfc_symbol *sym)
+{
+  fprintf (dumpfile, "int (*%s (", sym->binding_label);
+  write_formal_arglist (sym, 1);
+  fputs (")) ();\n", dumpfile);
+}
+
 /* Write out a procedure, including its arguments.  */
 static void
 write_proc (gfc_symbol *sym, bool bind_c)
@@ -4552,7 +4566,13 @@ write_interop_decl (gfc_symbol *sym)
   else if (sym->attr.flavor == FL_DERIVED)
     write_type (sym);
   else if (sym->attr.flavor == FL_PROCEDURE)
-    write_proc (sym, true);
+    {
+      if (sym->ts.type == BT_DERIVED
+	  && strcmp (sym->ts.u.derived->name, "c_funptr") == 0)
+	write_funptr_fcn (sym);
+      else
+	write_proc (sym, true);
+    }
 }
 
 /* This section deals with dumping the global symbol tree.  */
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 34c8210f66a..efc059908f7 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -12187,6 +12187,34 @@ caf_possible_reallocate (gfc_expr *e)
   return last_arr_ref && last_arr_ref->u.ar.type == AR_FULL;
 }
 
+/*  Handle C_FUNPTR assignments, for generating C prototypes and for warning if
+    pointers are assigned to procedures with different interfaces.  */
+
+static void
+check_c_funptr_assign_interface (gfc_expr *lhs, gfc_expr *rhs)
+{
+  gfc_symbol *lsym, *l_derived_sym, *rsym;
+  if (lhs->expr_type != EXPR_VARIABLE)
+    return;
+
+  lsym = lhs->symtree->n.sym;
+  if (lsym->ts.type != BT_DERIVED || !lsym->attr.is_bind_c)
+    return;
+
+  l_derived_sym = lsym->ts.u.derived;
+
+  if (!l_derived_sym->attr.is_c_interop
+      || strcmp (l_derived_sym->name, "c_funptr") != 0)
+    return;
+
+  if (rhs->expr_type != EXPR_FUNCTION || !rhs->is_c_interop)
+    return;
+
+  rsym = rhs->symtree->n.sym;
+
+  fprintf (stderr,"%p %p\n", (void *) lhs, (void *) rhs);
+}
+
 /* Does everything to resolve an ordinary assignment.  Returns true
    if this is an interface assignment.  */
 static bool
@@ -12437,6 +12465,9 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
 
   gfc_check_assign (lhs, rhs, 1);
 
+  if (warn_external_argument_mismatch)
+    check_c_funptr_assign_interface (lhs, rhs);
+      
   return false;
 }
 

Reply via email to