void check_function_results(int p, int enclosing_defproc, int *resultcount)
{
  if ((p == -1) || (astop(p) == -1)) return;

  // Note that it was easier to have the Populate_Types module handle the AST_Call
  // item, where the caller of a procedure is given a link to the procedure
  // definition, in order to check the return type, and to pass critical
  // info about stack usage to the PRECALL and CALL macros

  switch (astop(p)) {
  case AST_DefProc: // leftchild() = ast_type of result
    {
      int count = 0;
      check_function_results(nthchild(p,3), p, &count);
      if ((count == 0) && (rightchild(leftchild(p)) != 0)) {
        error_line(c[leftchild(rightchild(p))].l);
        fprintf(stderr, "* Error: non-void function %s does not return a result\n", c[leftchild(rightchild(p))].s);
      }
    }
    break;

  case AST_ReturnResult:
    if (TYPEINFO(p) == -1) TYPEINFO(p) = leftchild(enclosing_defproc); // for casting/checking result type
    if (rightchild(p) == -1) rightchild(p) = leftchild(enclosing_defproc); 
    fprintf(stdout, "setting result type for %d to %d\n", p, TYPEINFO(p));
    //"returns result in void procedure"
    *resultcount = 1 + *resultcount;
    break;

  case AST_Return:
    //"result value missing in non-void procedure"
    *resultcount = *resultcount + 1;
    break;

  default:
    break;
  }

  {
    int i;
    int disp;
    int this;
    // recursively search for more proc/fn bodies throughout the code:
    // We could alternatively call one level of this in grammar.c after
    // compiling the proc

    disp = op[astop(p)-AST_BASE].Display_Children;
    this = 1<<(children(p)-1);
    for (i = 0; i < children(p); i++) {
      if ((nthchild(p, i) != -1) && (disp&this)) {
        if (astop(nthchild(p, i)) != AST_TYPE_Struct)
          check_function_results(nthchild(p, i), enclosing_defproc, resultcount);
      }
      this = this>>1;
    }
  }
}
