[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gcc-fortran
Subject:    [PATCH, FORTRAN] Fix PR fortran/60191
From:       Bernd Edlinger <bernd.edlinger () hotmail ! de>
Date:       2014-03-31 7:03:46
Message-ID: DUB129-W10EE5BE36DE63EDFF5DBC4E4630 () phx ! gbl
[Download RAW message or body]

Hi,

in the test cases dynamic_dispatch_1.f03 and dynamic_dispatch_3.f04 there is \
recursive procedure type, make_real, the front-end generates the equivalent of 

extern "C" float make_real(t1*, ...);

for the call statements, but uses

extern "C" float make_real(t1*)
{
}

for the procedure itself, which is the first invocation of gfc_get_function_type.

In the case of arm-linux-gnueabihf these prototypes are not equivalent, see arm.c:

  if (TARGET_AAPCS_BASED)
    {
      /* Detect varargs functions.  These always use the base rules
         (no argument is ever a candidate for a co-processor
         register).  */
      bool base_rules = stdarg_p (type);

      if (user_convention)
        {
          if (user_pcs> ARM_PCS_AAPCS_LOCAL)
            sorry ("non-AAPCS derived PCS variant");
          else if (base_rules && user_pcs != ARM_PCS_AAPCS)
            error ("variadic functions must use the base AAPCS variant");
        }

      if (base_rules)
        return ARM_PCS_AAPCS;


But if above stdarg_p  returns false, the calling convention is: arm_pcs_default = \
ARM_PCS_AAPCS_VFP. To fix this it is sufficient to generate a prototype like

extern "C" float make_real(...);

in case of a recursion or when the argument types are not known, which makes strarg_p \
return false.

note that:

 float func(...); // this syntax is valid only in C++

returns the result in s0, because it is not really considered a variadic,
while

 float func(int, ...);

is incompatible on this target and uses r0 for the result.


Boot-strapped and Regression-tested on arm-linux-gnueabihf and x86_64-linux-gnu.
OK for trunk?


Thanks
Bernd. 		 	   		  


["changelog-pr60191.txt" (text/plain)]

2014-03-31  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	PR fortran/60191
	* fortran/trans-types.c (gfc_get_function_type): In case of recursion
	build a variadic function type with empty argument list instead of a
	stdarg-like function type with incomplete argument list.


["patch-pr60191.diff" (application/octet-stream)]

--- gcc/fortran/trans-types.c	2014-03-06 22:45:31.000000000 +0100
+++ gcc/fortran/trans-types.c	2014-03-25 14:15:36.774635331 +0100
@@ -2714,11 +2714,11 @@ tree
 gfc_get_function_type (gfc_symbol * sym)
 {
   tree type;
-  vec<tree, va_gc> *typelist;
+  vec<tree, va_gc> *typelist = NULL;
   gfc_formal_arglist *f;
   gfc_symbol *arg;
-  int alternate_return;
-  bool is_varargs = true, recursive_type = false;
+  int alternate_return = 0;
+  bool is_varargs = true;
 
   /* Make sure this symbol is a function, a subroutine or the main
      program.  */
@@ -2730,15 +2730,12 @@ gfc_get_function_type (gfc_symbol * sym)
   if (sym->backend_decl == NULL)
     sym->backend_decl = error_mark_node;
   else if (sym->backend_decl == error_mark_node)
-    recursive_type = true;
+    goto arg_type_list_done;
   else if (sym->attr.proc_pointer)
     return TREE_TYPE (TREE_TYPE (sym->backend_decl));
   else
     return TREE_TYPE (sym->backend_decl);
 
-  alternate_return = 0;
-  typelist = NULL;
-
   if (sym->attr.entry_master)
     /* Additional parameter for selecting an entry point.  */
     vec_safe_push (typelist, gfc_array_index_type);
@@ -2786,13 +2783,6 @@ gfc_get_function_type (gfc_symbol * sym)
 
 	  if (arg->attr.flavor == FL_PROCEDURE)
 	    {
-	      /* We don't know in the general case which argument causes
-		 recursion.  But we know that it is a procedure.  So we give up
-		 creating the procedure argument type list at the first
-		 procedure argument.  */
-	      if (recursive_type)
-	        goto arg_type_list_done;
-
 	      type = gfc_get_function_type (arg);
 	      type = build_pointer_type (type);
 	    }
@@ -2846,11 +2836,11 @@ gfc_get_function_type (gfc_symbol * sym)
       || sym->attr.if_source != IFSRC_UNKNOWN)
     is_varargs = false;
 
-arg_type_list_done:
-
-  if (!recursive_type && sym->backend_decl == error_mark_node)
+  if (sym->backend_decl == error_mark_node)
     sym->backend_decl = NULL_TREE;
 
+arg_type_list_done:
+
   if (alternate_return)
     type = integer_type_node;
   else if (!sym->attr.function || gfc_return_by_reference (sym))
@@ -2888,7 +2878,7 @@ arg_type_list_done:
   else
     type = gfc_sym_type (sym);
 
-  if (is_varargs || recursive_type)
+  if (is_varargs)
     type = build_varargs_function_type_vec (type, typelist);
   else
     type = build_function_type_vec (type, typelist);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic