diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 428885fd2c7bfbb58574cc21073e0a6f3dc67ade..b796a4128f60a161265a5e31684e900b3242d946 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -3291,6 +3291,7 @@ parser_enter_program( const char *funcname_,
     }
 
   enter_program_common(funcname, funcname_);
+  current_function->is_function = is_function;
 
   TRACE1
     {
@@ -4727,7 +4728,7 @@ parser_move(size_t ntgt, cbl_refer_t *tgts, cbl_refer_t src, cbl_round_t rounded
 
 static
 tree
-field_type_to_tree_type(cbl_field_t *field)
+field_type_to_tree_type(cbl_field_t *field, bool is_function)
   {
   /*  This routine is used to determine what action is taken with type of a 
       CALL ... USING <var> and the matching PROCEDURE DIVISION USING <var> of
@@ -4735,16 +4736,24 @@ field_type_to_tree_type(cbl_field_t *field)
 
       This routine looks at a field.  If that field can be handled as a simple
       type of no more than 64-bits, the tree form of that type is is returned.
-  
+      
+      When a field can't be handled as a 64-bit variant, we return NULL.  In
+      that case, our caller will assume the variable being transferred is a
+      64-bit pointer to a malloced buffer, and will generate code accordingly.
       */
 
-
   // This maps a Fldxxx to a C-style variable type:
   switch(field->type)
     {
     case FldGroup:
     case FldAlphanumeric:
     case FldAlphaEdited:
+      if( is_function )
+        {
+        // For COBOL functions, these types of variables are treated as malloced
+        // buffers.
+        return NULL;
+        }
       return CHAR_P;
 
     case FldNumericEdited:
@@ -4754,9 +4763,17 @@ field_type_to_tree_type(cbl_field_t *field)
     case FldNumericBin5:
     case FldIndex:
     case FldPointer:
+      if( field->data.capacity > 8 )
+        {
+        return NULL;
+        }
       return SSIZE_T;
 
     case FldFloat:
+      if( field->data.capacity > 8 )
+        {
+        return NULL;
+        }
       return DOUBLE;
 
     case FldInvalid:
@@ -4847,7 +4864,8 @@ parser_exit(void)
 
   if( current_function->returning )
     {
-    tree return_type  = field_type_to_tree_type(current_function->returning);
+    tree return_type  = field_type_to_tree_type(current_function->returning,
+                                                current_function->is_function);
 
     if( return_type == CHAR_P )
       {
@@ -10749,7 +10767,7 @@ parser_call(   cbl_refer_t name,
               member(returned.refer_decl_node, "qual_data"));
     gg_assign(returned_length,
               member(returned.refer_decl_node, "qual_size"));
-    returned_value_type = field_type_to_tree_type(returned.field);
+    returned_value_type = field_type_to_tree_type(returned.field, is_function);
     }
   else
     {
@@ -10758,7 +10776,6 @@ parser_call(   cbl_refer_t name,
 
   tree function_handle = function_handle_from_name(name, narg);
 
-
   IF( function_handle,
       ne_op,
       gg_cast(TREE_TYPE(function_handle), null_pointer_node) )
@@ -10855,19 +10872,26 @@ parser_call(   cbl_refer_t name,
     tree returned_value;
     if( returned.field )
       {
-      // We are expecting a return value:
-      returned_value = gg_define_variable(returned_value_type);
+      // We are expecting a return value.
+      
+      // It can come in two flavors:  Either it is a castable type of no more
+      // than 64 bits.  But when returned_value_type is NULL at this point, we
+      // are expecting a pointer to a malloced memory buffer that we will need
+      // to copy.
+      
+      tree rvt = returned_value_type ? returned_value_type : UCHAR_P ;
+      returned_value = gg_define_variable(rvt);
 
       // Before doing the call, we save the COBOL program_state:
       push_program_state();
-      gg_assign(returned_value, gg_cast(returned_value_type, call_expr));
+      gg_assign(returned_value, gg_cast(rvt, call_expr));
       // And after the call, we restore it:
       pop_program_state();
 
-    // Because the CALL had a RETURNING clause, RETURN-CODE doesn't return a
-    // value.  So, we make sure it is zero
-    cbl_field_t *return_code = cbl_field_of(symbol_at(return_code_register()));
-    gg_call(VOID,
+      // Because the CALL had a RETURNING clause, RETURN-CODE doesn't return a
+      // value.  So, we make sure it is zero
+      cbl_field_t *return_code = cbl_field_of(symbol_at(return_code_register()));
+      gg_call(VOID,
             "__gg__int128_to_field",
             5,
             gg_get_address_of(return_code->var_decl_node),
@@ -10876,7 +10900,14 @@ parser_call(   cbl_refer_t name,
             build_int_cst_type(INT, truncation_e),
             null_pointer_node );
 
-      if(returned_value_type == CHAR_P)
+      if( returned_value_type == NULL )
+        {
+        // What we got back from the call was a pointer to a malloced memoryb
+        // buffer.  We copy that into our target, and then we free that buffer.
+        gg_memcpy(returned_location, returned_value, returned_length);
+        gg_free(returned_value);
+        }
+      else if(returned_value_type == CHAR_P)
         {
         // The returned value is to a null-terminated string:
         IF( returned_value,
diff --git a/gcc/cobol/gengen.h b/gcc/cobol/gengen.h
index 05e5579dcdec41d6acf908b8bab53e27131584b9..1f65ac9dbe234ced38c7ddf612b62fe3c7ed145a 100644
--- a/gcc/cobol/gengen.h
+++ b/gcc/cobol/gengen.h
@@ -119,6 +119,13 @@ enum gg_variable_scope_t {
 
 struct gg_function_t
     {
+    // Nomenclature Alert:  The "function" in gg_function_t was chosen
+    // originally because a PROGRAM-ID is implemented as a C-style "function",
+    // and there are numerous tree variables that refer to "functions".
+    // Eventually the COBOL compiler grew to handle not just COBOL PROGRAM-ID
+    // "programs", but also user-defined COBOL FUNCTION-ID "functions".  This
+    // inevitably is confusing.  Sorry about that.
+
     // This structure contains state variables for a single function.
 
     const char *our_unmangled_name;
@@ -223,6 +230,10 @@ struct gg_function_t
     // back to the first declarative of its immediate parent.
     tree first_declarative_section;
 
+    // is_function is true when this structure is describing a COBOL FUNCTION-ID
+    // and is false for a PROGRAM-ID
+    bool is_function;
+
     };
 
 struct cbl_translation_unit_t