PATCH: PR2924

Mark Mitchell mark@codesourcery.com
Mon Jun 4 23:49:00 GMT 2001


This patch fixes PR2924, which is an evil conjunction of two of my
least favorite GNU C extensions: nested functions and variable-sized
types.  Ugh.

Here's the fix, which is pretty ugly itself.  This could be done in
better ways -- but not without some substantial reworking of the
front-end.

Bootstrapped and tested on i686-pc-linux-gnu, installed on the
mainline and on the branch.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2001-06-04  Mark Mitchell  <mark@codesourcery.com>

	* c-tree.h (lang_decl): Add pending_sizes fields.
	* c-decl.c (store_parm_decls): Save pending_sizes away for nested
	functions.
	(c_expand_body): Expand them.
	(lang_mark_tree): Mark lang_decl:pending_sizes.
	* function.c (expand_pending_sizes): New function, broken out 
	from ...
	(expand_function_start): ... here.
	* tree.h (expand_pending_sizes): Declare it.

Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.207.2.10
diff -c -p -r1.207.2.10 c-decl.c
*** c-decl.c	2001/05/21 18:08:50	1.207.2.10
--- c-decl.c	2001/06/05 06:33:21
*************** store_parm_decls ()
*** 6083,6088 ****
--- 6083,6091 ----
    /* Nonzero if this definition is written with a prototype.  */
    int prototype = 0;
  
+   /* The function containing FNDECL, if any.  */
+   tree context = decl_function_context (fndecl);
+ 
    if (specparms != 0 && TREE_CODE (specparms) != TREE_LIST)
      {
        /* This case is when the function was defined with an ANSI prototype.
*************** store_parm_decls ()
*** 6451,6464 ****
    gen_aux_info_record (fndecl, 1, 0, prototype);
  
    /* Initialize the RTL code for the function.  */
- 
    init_function_start (fndecl, input_filename, lineno);
  
    /* Begin the statement tree for this function.  */
    DECL_LANG_SPECIFIC (current_function_decl)
!     =((struct lang_decl *) ggc_alloc (sizeof (struct lang_decl)));
    begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl));
  
    /* This function is being processed in whole-function mode.  */
    cfun->x_whole_function_mode_p = 1;
  
--- 6454,6481 ----
    gen_aux_info_record (fndecl, 1, 0, prototype);
  
    /* Initialize the RTL code for the function.  */
    init_function_start (fndecl, input_filename, lineno);
  
    /* Begin the statement tree for this function.  */
    DECL_LANG_SPECIFIC (current_function_decl)
!     =((struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl)));
    begin_stmt_tree (&DECL_SAVED_TREE (current_function_decl));
  
+   /* If this is a nested function, save away the sizes of any
+      variable-size types so that we can expand them when generating
+      RTL.  */
+   if (context)
+     {
+       tree t;
+ 
+       DECL_LANG_SPECIFIC (fndecl)->pending_sizes 
+ 	= nreverse (get_pending_sizes ());
+       for (t = DECL_LANG_SPECIFIC (fndecl)->pending_sizes;
+ 	   t;
+ 	   t = TREE_CHAIN (t))
+ 	SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = context;
+     }
+ 
    /* This function is being processed in whole-function mode.  */
    cfun->x_whole_function_mode_p = 1;
  
*************** c_expand_body (fndecl, nested_p)
*** 6702,6710 ****
    if (flag_syntax_only)
      return;
  
-   /* Squirrel away our current state.  */
    if (nested_p)
!     push_function_context ();
  
    /* Initialize the RTL code for the function.  */
    current_function_decl = fndecl;
--- 6719,6732 ----
    if (flag_syntax_only)
      return;
  
    if (nested_p)
!     {
!       /* Make sure that we will evaluate variable-sized types involved
! 	 in our function's type.  */
!       expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes);
!       /* Squirrel away our current state.  */
!       push_function_context ();
!     }
  
    /* Initialize the RTL code for the function.  */
    current_function_decl = fndecl;
*************** c_expand_body (fndecl, nested_p)
*** 6739,6745 ****
    /* Allow the body of the function to be garbage collected.  */
    DECL_SAVED_TREE (fndecl) = NULL_TREE;
  
!   /* We hard-wired immediate_size_expand to zero in start_function.
       expand_function_end will decrement this variable.  So, we set the
       variable to one here, so that after the decrement it will remain
       zero.  */
--- 6761,6767 ----
    /* Allow the body of the function to be garbage collected.  */
    DECL_SAVED_TREE (fndecl) = NULL_TREE;
  
!   /* We hard-wired immediate_size_expand to zero above.
       expand_function_end will decrement this variable.  So, we set the
       variable to one here, so that after the decrement it will remain
       zero.  */
*************** lang_mark_tree (t)
*** 7034,7039 ****
--- 7056,7062 ----
      {
        ggc_mark (DECL_LANG_SPECIFIC (t));
        c_mark_lang_decl (&DECL_LANG_SPECIFIC (t)->base);
+       ggc_mark_tree (DECL_LANG_SPECIFIC (t)->pending_sizes);
      }
  }
  
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.54
diff -c -p -r1.54 c-tree.h
*** c-tree.h	2000/12/20 18:18:24	1.54
--- c-tree.h	2001/06/05 06:33:21
*************** struct lang_identifier
*** 42,53 ****
    enum rid rid_code;
  };
  
! /* Wrapping c_lang_decl in another struct is an unfortunate
!    necessity.  */
  
  struct lang_decl
  {
    struct c_lang_decl base;
  };
  
  /* Macros for access to language-specific slots in an identifier.  */
--- 42,56 ----
    enum rid rid_code;
  };
  
! /* Language-specific declaration information.  */
  
  struct lang_decl
  {
    struct c_lang_decl base;
+   /* The return types and parameter types may have variable size.
+      This is a list of any SAVE_EXPRs that need to be evaluated to
+      compute those sizes.  */
+   tree pending_sizes;
  };
  
  /* Macros for access to language-specific slots in an identifier.  */
Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.250.2.10
diff -c -p -r1.250.2.10 function.c
*** function.c	2001/05/18 07:26:05	1.250.2.10
--- function.c	2001/06/05 06:33:24
*************** expand_main_function ()
*** 6263,6268 ****
--- 6263,6291 ----
  
  extern struct obstack permanent_obstack;
  
+ /* The PENDING_SIZES represent the sizes of variable-sized types.
+    Create RTL for the various sizes now (using temporary variables),
+    so that we can refer to the sizes from the RTL we are generating
+    for the current function.  The PENDING_SIZES are a TREE_LIST.  The
+    TREE_VALUE of each node is a SAVE_EXPR.  */
+ 
+ void
+ expand_pending_sizes (pending_sizes)
+      tree pending_sizes;
+ {
+   tree tem;
+ 
+   /* Evaluate now the sizes of any types declared among the arguments.  */
+   for (tem = pending_sizes; tem; tem = TREE_CHAIN (tem))
+     {
+       expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
+ 		   EXPAND_MEMORY_USE_BAD);
+       /* Flush the queue in case this parameter declaration has
+ 	 side-effects.  */
+       emit_queue ();
+     }
+ }
+ 
  /* Start the RTL for a new function, and set variables used for
     emitting RTL.
     SUBR is the FUNCTION_DECL node.
*************** expand_function_start (subr, parms_have_
*** 6497,6510 ****
    tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
  
    /* Evaluate now the sizes of any types declared among the arguments.  */
!   for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
!     {
!       expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
! 		   EXPAND_MEMORY_USE_BAD);
!       /* Flush the queue in case this parameter declaration has
! 	 side-effects.  */
!       emit_queue ();
!     }
  
    /* Make sure there is a line number after the function entry setup code.  */
    force_next_line_note ();
--- 6520,6526 ----
    tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
  
    /* Evaluate now the sizes of any types declared among the arguments.  */
!   expand_pending_sizes (nreverse (get_pending_sizes ()));
  
    /* Make sure there is a line number after the function entry setup code.  */
    force_next_line_note ();
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.223.2.10
diff -c -p -r1.223.2.10 tree.h
*** tree.h	2001/05/22 03:01:50	1.223.2.10
--- tree.h	2001/06/05 06:33:37
*************** extern void print_obstack_name		PARAMS (
*** 2727,2732 ****
--- 2727,2733 ----
  #endif
  extern void expand_function_end		PARAMS ((const char *, int, int));
  extern void expand_function_start	PARAMS ((tree, int));
+ extern void expand_pending_sizes        PARAMS ((tree));
  
  extern int real_onep			PARAMS ((tree));
  extern int real_twop			PARAMS ((tree));
Index: testsuite/gcc.c-torture/compile/20010605-1.c
===================================================================
RCS file: 20010605-1.c
diff -N 20010605-1.c
*** /dev/null	Tue May  5 13:32:27 1998
--- 20010605-1.c	Mon Jun  4 23:33:39 2001
***************
*** 0 ****
--- 1,15 ----
+ int
+ main (int argc, char **argv)
+ {
+   int size = 10;
+ 
+   typedef struct {
+     char val[size];
+   } block;
+   block retframe_block()
+     {
+       return *(block*)0;
+     }
+ 
+   return 0;
+ }



More information about the Gcc-patches mailing list