*** gcc-2.7.2-orig/c-common.c	Thu Nov 16 00:54:41 1995
--- gcc-2.7.2/c-common.c	Thu Nov 16 16:37:08 1995
***************
*** 20,25 ****
--- 20,27 ----
  
  #include "config.h"
  #include "tree.h"
+ #include "rtl.h"
+ #include "c-bounds.h"
  #include "c-lex.h"
  #include "c-tree.h"
  #include "flags.h"
***************
*** 2137,2142 ****
--- 2139,2155 ----
  	     truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)),
  	     truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)),
  	     0));
+ 
+   /* In bounds checking mode, if we evaluate the truthvalue of a pointer we
+    * want to check the pointer is not ILLEGAL or otherwise invalid. We build
+    * the necessary code here.	-- RWMJ
+    */
+   if (bounds_checking_enabled)
+     {
+       enum tree_code code = TREE_CODE (TREE_TYPE (expr));
+       if (code == POINTER_TYPE || code == ARRAY_TYPE || code == FUNCTION_TYPE)
+ 	return bounds_build_truthvalue_conversion (expr);
+     }
  
    return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
  }
*** gcc-2.7.2-orig/c-decl.c	Thu Nov 16 00:54:43 1995
--- gcc-2.7.2/c-decl.c	Wed Jan 10 14:44:11 1996
***************
*** 541,546 ****
--- 541,557 ----
  
  int warn_missing_braces;
  
+ /* Bounds checking is turned off temporarily inside static initializers by
+  * c-typeck.c:start_init using the following flag.	(RWMJ)
+  */
+ 
+ int bounds_in_static_decl;
+ 
+ /* Pop level if it was pushed in bounds_build_args ().	(RWMJ)
+  */
+ 
+ int bounds_poplevel = 0;
+ 
  /* Nonzero means `$' can be in an identifier.
     See cccp.c for reasons why this breaks some obscure ANSI C programs.  */
  
***************
*** 727,732 ****
--- 738,749 ----
        warn_parentheses = 1;
        warn_missing_braces = 1;
      }
+   /* Flags to handle bounds checking. (RWMJ). */
+   else if (!strcmp (p, "-fbounds-checking"))
+     {
+       bounds_checking_enabled = 1;
+       flag_no_builtin = 1;		/* So we can check mem* functions too*/
+     }
    else
      return 0;
  
***************
*** 3272,3277 ****
--- 3289,3405 ----
  		    NULL_PTR);
  #endif
  
+   if (bounds_checking_enabled) {
+     /* Create a prototype for the functions __bounds_check... (RWMJ) */
+     tree voidptr_ftype_any
+       = build_function_type (ptr_type_node, NULL_TREE);
+     tree int_ftype_any
+       = build_function_type (integer_type_node, NULL_TREE);
+ /*    tree void_ftype_any
+       = build_function_type (void_type_node, NULL_TREE); */
+ 
+     builtin_function ("__bounds_check_ptr_plus_int",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_array_reference",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_component_reference",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_diff",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_reference",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_lt_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_le_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_gt_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_ge_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_eq_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_ne_ptr",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_postinc",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_preinc",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_postdec",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_predec",
+ 		      voidptr_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_true",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_check_ptr_false",
+ 		      int_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_note_constructed_object",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_note_constructed_private_table",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_push_function",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_pop_function",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_add_param_object",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_add_stack_object",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_delete_stack_object",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+     builtin_function ("__bounds_initialize_library",
+ 		      void_ftype_any,
+ 		      NOT_BUILT_IN,
+ 		      NULL_PTR);
+   }
+ 
    pedantic_lvalues = pedantic;
  
    /* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
***************
*** 3545,3550 ****
--- 3673,3688 ----
        DECL_INITIAL (decl) = error_mark_node;
      }
  
+   /* In bounds checking mode, we will always have an initializer for local
+    * variable declarations. So set DECL_INITIAL to indicate this to `pushdecl'.
+    * (RWMJ, 29/1/95)
+    */
+   if (bounds_checking_enabled
+       && current_binding_level != global_binding_level
+       && TREE_CODE (decl) == VAR_DECL
+       && !DECL_EXTERNAL (decl))
+     DECL_INITIAL (decl) = error_mark_node;
+ 
    /* If this is a function declaration, write a record describing it to the
       prototypes file (if requested).  */
  
***************
*** 3735,3740 ****
--- 3873,3889 ----
  	DECL_RTL (decl) = 0;
        }
  
+ 
+   /* In bounds checking mode, if this is a local variable declaration, then
+    * we create or alter the initializer so that it has the side effect of
+    * calling __bounds_add_stack_object.
+    */
+   if (bounds_checking_enabled
+       && current_binding_level != global_binding_level
+       && TREE_CODE (decl) == VAR_DECL
+       && !DECL_EXTERNAL (decl))
+     bounds_frig_decl_initial (decl);
+ 
    /* Output the assembler code and/or RTL code for variables and functions,
       unless the type is an undefined structure or union.
       If not, it will get done when the type is completed.  */
***************
*** 3776,3781 ****
--- 3925,3936 ----
  	  /* Compute and store the initial value.  */
  	  if (TREE_CODE (decl) != FUNCTION_DECL)
  	    expand_decl_init (decl);
+ 	  /* If bounds checking, compute and store a clean-up for it. */
+ 	  if (bounds_checking_enabled
+ 	      && TREE_CODE (decl) != FUNCTION_DECL
+ 	      && !DECL_EXTERNAL (decl)
+ 	      && !TREE_STATIC (decl))
+ 	    bounds_expand_decl_cleanup (decl);
  	}
      }
  
***************
*** 6587,6592 ****
--- 6742,6753 ----
        && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0
        && DECL_CONTEXT (fndecl) == NULL_TREE)
      expand_main_function ();
+ 
+   /* In bounds checking mode, emit various function calls here so we can
+    * find the function's arguments.
+    */
+   if (bounds_checking_enabled)
+     bounds_build_args ();
  }
  
  /* SPECPARMS is an identifier list--a chain of TREE_LIST nodes
***************
*** 6748,6753 ****
--- 6909,6925 ----
  {
    register tree fndecl = current_function_decl;
  
+   /* In bounds checking mode, we may have introduced an extra binding
+    * contour in `bounds_build_args'. We pop it here.
+    */
+   if (bounds_checking_enabled && bounds_poplevel)
+     {
+       expand_end_bindings (getdecls (), 1, 0);
+       poplevel (1, 0, 0);
+       pop_momentary ();
+       bounds_poplevel = 0;
+     }
+ 
  /*  TREE_READONLY (fndecl) = 1;
      This caused &foo to be of type ptr-to-const-function
      which then got a warning when stored in a ptr-to-function variable.  */
***************
*** 6782,6787 ****
--- 6954,6972 ----
  
    /* Generate rtl for function exit.  */
    expand_function_end (input_filename, lineno, 0);
+ 
+   /* We now have the complete rtl for the function. In bounds checking mode,
+    * we want to delete redundant calls to:
+    *	__bounds_push_function
+    *	__bounds_pop_function
+    *	__bounds_add_param_object
+    *	__bounds_add_stack_object
+    *	__bounds_delete_stack_object
+    * if it turns out that these are unnecessary in this function. Do that
+    * now.					(RWMJ)
+    */
+   if (bounds_checking_enabled)
+     bounds_delete_redundant_calls (fndecl);
  
    /* So we can tell if jump_optimize sets it to 1.  */
    can_reach_end = 0;
*** gcc-2.7.2-orig/c-lang.c	Thu Nov 16 00:54:44 1995
--- gcc-2.7.2/c-lang.c	Thu Nov 16 16:37:11 1995
***************
*** 24,29 ****
--- 24,32 ----
  #include <stdio.h>
  #include "input.h"
  
+ #include "rtl.h"
+ #include "c-bounds.h"
+ 
  /* Each of the functions defined here
     is an alternative to a function in objc-actions.c.  */
     
***************
*** 137,142 ****
--- 140,150 ----
    extern tree get_file_function_name ();
    extern tree build_function_call                 PROTO((tree, tree));
    tree void_list_node = build_tree_list (NULL_TREE, void_type_node);
+ 
+   /* Build bounds-checking constructors for this file. (RWMJ)*/
+   if (bounds_checking_enabled)
+     bounds_build_static_constructors ();
+ 
  #ifndef ASM_OUTPUT_CONSTRUCTOR
    if (static_ctors)
      {
*** gcc-2.7.2-orig/c-parse.in	Thu Nov 16 00:54:44 1995
--- gcc-2.7.2/c-parse.in	Thu Nov 16 16:37:12 1995
***************
*** 69,74 ****
--- 69,77 ----
  #include "c-tree.h"
  #include "flags.h"
  
+ extern int bounds_checking_enabled, bounds_in_static_decl;
+ tree bounds_build_component_indirect_ref PROTO((tree, tree));
+ 
  #ifdef MULTIBYTE_CHARS
  #include <stdlib.h>
  #include <locale.h>
***************
*** 812,830 ****
  		}
  	| primary POINTSAT identifier
  		{
!                   tree expr = build_indirect_ref ($1, "->");
  
  ifobjc
!                   if (doing_objc_thang)
!                     {
! 		      if (is_public (expr, $3))
! 			$$ = build_component_ref (expr, $3);
  		      else
- 			$$ = error_mark_node;
- 		    }
-                   else
  end ifobjc
!                     $$ = build_component_ref (expr, $3);
  		}
  	| primary PLUSPLUS
  		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
--- 815,841 ----
  		}
  	| primary POINTSAT identifier
  		{
! 		  if (bounds_checking_enabled &&
! 		      !bounds_in_static_decl)
! 		    {
! 		      $$ = bounds_build_component_indirect_ref ($1, $3);
! 		    }
! 		  else
! 		    {
! 		      tree expr = build_indirect_ref ($1, "->");
  
  ifobjc
!                       if (doing_objc_thang)
! 			{
! 			  if (is_public (expr, $3))
! 			    $$ = build_component_ref (expr, $3);
! 			  else
! 			    $$ = error_mark_node;
! 			}
  		      else
  end ifobjc
!                         $$ = build_component_ref (expr, $3);
! 		    }
  		}
  	| primary PLUSPLUS
  		{ $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
*** gcc-2.7.2-orig/c-tree.h	Thu Jun 15 07:13:40 1995
--- gcc-2.7.2/c-tree.h	Tue Jul  4 10:21:03 1995
***************
*** 487,490 ****
--- 487,496 ----
  
  extern int doing_objc_thang;
  
+ /* Flags for bounds checking. (RWMJ). */
+ 
+ extern int bounds_checking_enabled;
+ extern int bounds_checking_reuse_heap;
+ extern int bounds_checking_reuse_stack;
+ 
  #endif /* not _C_TREE_H */
*** gcc-2.7.2-orig/c-typeck.c	Thu Nov 16 00:54:46 1995
--- gcc-2.7.2/c-typeck.c	Thu Nov 16 16:37:15 1995
***************
*** 31,37 ****
--- 31,39 ----
  #include "config.h"
  #include <stdio.h>
  #include "tree.h"
+ #include "rtl.h"
  #include "c-tree.h"
+ #include "c-bounds.h"
  #include "flags.h"
  #include "output.h"
  
***************
*** 1303,1309 ****
  
  /* Given an expression PTR for a pointer, return an expression
     for the value pointed to.
!    ERRORSTRING is the name of the operator to appear in error messages.  */
  
  tree
  build_indirect_ref (ptr, errorstring)
--- 1305,1319 ----
  
  /* Given an expression PTR for a pointer, return an expression
     for the value pointed to.
!    ERRORSTRING is the name of the operator to appear in error messages.
! 
!    For bounds checked code, we generate a call to:
!      void*  __bounds_check_reference (void *pointer, size_t size,
!                                       char *filename, int line);
!    This function checks that the reference will be successful (else
!    aborts with an error message). We then make the reference ourselves
!    as usual.
!    */
  
  tree
  build_indirect_ref (ptr, errorstring)
***************
*** 1315,1352 ****
  
    if (TREE_CODE (type) == POINTER_TYPE)
      {
        if (TREE_CODE (pointer) == ADDR_EXPR
  	  && !flag_volatile
  	  && (TREE_TYPE (TREE_OPERAND (pointer, 0))
  	      == TREE_TYPE (type)))
  	return TREE_OPERAND (pointer, 0);
        else
! 	{
! 	  tree t = TREE_TYPE (type);
! 	  register tree ref = build1 (INDIRECT_REF,
! 				      TYPE_MAIN_VARIANT (t), pointer);
! 
! 	  if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)
! 	    {
! 	      error ("dereferencing pointer to incomplete type");
! 	      return error_mark_node;
! 	    }
! 	  if (TREE_CODE (t) == VOID_TYPE)
! 	    warning ("dereferencing `void *' pointer");
  
! 	  /* We *must* set TREE_READONLY when dereferencing a pointer to const,
! 	     so that we get the proper error message if the result is used
! 	     to assign to.  Also, &* is supposed to be a no-op.
! 	     And ANSI C seems to specify that the type of the result
! 	     should be the const type.  */
! 	  /* A de-reference of a pointer to const is not a const.  It is valid
! 	     to change it via some other pointer.  */
! 	  TREE_READONLY (ref) = TYPE_READONLY (t);
! 	  TREE_SIDE_EFFECTS (ref)
! 	    = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
! 	  TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
! 	  return ref;
  	}
      }
    else if (TREE_CODE (pointer) != ERROR_MARK)
      error ("invalid type argument of `%s'", errorstring);
--- 1325,1365 ----
  
    if (TREE_CODE (type) == POINTER_TYPE)
      {
+       tree ref;
+       tree t = TREE_TYPE (type);	/* type pointed to */
+ 
+       /* Look for expressions of the form &x and return x */
        if (TREE_CODE (pointer) == ADDR_EXPR
  	  && !flag_volatile
  	  && (TREE_TYPE (TREE_OPERAND (pointer, 0))
  	      == TREE_TYPE (type)))
  	return TREE_OPERAND (pointer, 0);
+       else if (bounds_checking_enabled
+ 	       && !bounds_in_static_decl)
+ 	ref = bounds_build_reference (ptr);
        else
! 	ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), pointer);
  
!       if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE)
! 	{
! 	  error ("dereferencing pointer to incomplete type");
! 	  return error_mark_node;
  	}
+       if (TREE_CODE (t) == VOID_TYPE)
+ 	warning ("dereferencing `void *' pointer");
+ 
+       /* We *must* set TREE_READONLY when dereferencing a pointer to const,
+ 	 so that we get the proper error message if the result is used
+ 	 to assign to.  Also, &* is supposed to be a no-op.
+ 	 And ANSI C seems to specify that the type of the result
+ 	 should be the const type.  */
+       /* A de-reference of a pointer to const is not a const.  It is valid
+ 	 to change it via some other pointer.  */
+       TREE_READONLY (ref) = TYPE_READONLY (t);
+       TREE_SIDE_EFFECTS (ref)
+ 	= TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer) || flag_volatile;
+       TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
+       return ref;
      }
    else if (TREE_CODE (pointer) != ERROR_MARK)
      error ("invalid type argument of `%s'", errorstring);
***************
*** 1360,1366 ****
     If A is a variable or a member, we generate a primitive ARRAY_REF.
     This avoids forcing the array out of registers, and can work on
     arrays that are not lvalues (for example, members of structures returned
!    by functions).  */
  
  tree
  build_array_ref (array, index)
--- 1373,1388 ----
     If A is a variable or a member, we generate a primitive ARRAY_REF.
     This avoids forcing the array out of registers, and can work on
     arrays that are not lvalues (for example, members of structures returned
!    by functions).
! 
!    In bounds checked mode, we generate a call to the function:
!      __bounds_check_array_reference
!    which checks the offset. It returns the address of the object which we
!    then directly reference. (RWMJ).
!    8/12/94: In some cases, generates `ptr_plus_int, ref' even in the case
!    &p[i] where the ref is unnecessary. Need to change this.
!    9/6/95: Fixed.
! */
  
  tree
  build_array_ref (array, index)
***************
*** 1441,1448 ****
  	    pedwarn ("ANSI C forbids subscripting non-lvalue array");
  	}
  
!       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
!       rval = build (ARRAY_REF, type, array, index);
        /* Array ref is const/volatile if the array elements are
           or if the array is.  */
        TREE_READONLY (rval)
--- 1463,1489 ----
  	    pedwarn ("ANSI C forbids subscripting non-lvalue array");
  	}
  
!       if (bounds_checking_enabled)
! 	{
! 	  /* In bounds checking modes, generate a call to __bounds_check_
! 	   * array_reference and an indirect ref. to that.
! 	   */
! 	  if (bounds_in_static_decl)
! 	    {
! 	      if (!bounds_can_test_array_reference_now (array, index))
! 		warning ("cannot check this array reference");
! 	      type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
! 	      rval = build (ARRAY_REF, type, array, index);
! 	    }
! 	  else
! 	    rval = bounds_build_array_reference (array, index);
! 	}
!       else
! 	{
! 	  type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
! 	  rval = build (ARRAY_REF, type, array, index);
! 	}
! 
        /* Array ref is const/volatile if the array elements are
           or if the array is.  */
        TREE_READONLY (rval)
***************
*** 1487,1492 ****
--- 1528,1536 ----
  	return error_mark_node;
        }
  
+     /* FIXME (RWMJ): This is wrong behaviour in pointer-checked modes. */
+     /* 9/6/95: I think this is right, in fact. */
+ 
      return build_indirect_ref (build_binary_op (PLUS_EXPR, ar, ind, 0),
  			       "array indexing");
    }
***************
*** 1949,1954 ****
--- 1993,2003 ----
    /* Nonzero means set RESULT_TYPE to the common type of the args.  */
    int common = 0;
  
+   /* Nonzero means we may build bounds checking code for a comparison
+    * operation (<, >, <=, >=, ==, !=) here.
+    */
+   int bounds_checked_comparison = 0;
+ 
    if (convert_p)
      {
        op0 = default_conversion (orig_op0);
***************
*** 2231,2254 ****
  
  	  if (result_type == NULL_TREE)
  	    result_type = ptr_type_node;
  	}
        else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
! 	       && integer_zerop (op1))
  	result_type = type0;
!       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
! 	       && integer_zerop (op0))
  	result_type = type1;
!       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	{
  	  result_type = type0;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
  	}
        else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
  	{
  	  result_type = type1;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
  	}
        break;
  
--- 2280,2309 ----
  
  	  if (result_type == NULL_TREE)
  	    result_type = ptr_type_node;
+ 
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
! 	       && integer_zerop (op1)) {
  	result_type = type0;
! 	bounds_checked_comparison = 1;
!       } else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
! 		 && integer_zerop (op0)) {
  	result_type = type1;
! 	bounds_checked_comparison = 1;
!       } else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	{
  	  result_type = type0;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
  	{
  	  result_type = type1;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
+ 	  bounds_checked_comparison = 1;
  	}
        break;
  
***************
*** 2299,2304 ****
--- 2354,2360 ----
  	      result_type = ptr_type_node;
  	      pedwarn ("comparison of distinct pointer types lacks a cast");
  	    }
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
  	       && integer_zerop (op1))
***************
*** 2306,2311 ****
--- 2362,2368 ----
  	  result_type = type0;
  	  if (pedantic || extra_warnings)
  	    pedwarn ("ordered comparison of pointer with integer zero");
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
  	       && integer_zerop (op0))
***************
*** 2313,2330 ****
--- 2370,2390 ----
  	  result_type = type1;
  	  if (pedantic)
  	    pedwarn ("ordered comparison of pointer with integer zero");
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
  	{
  	  result_type = type0;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
+ 	  bounds_checked_comparison = 1;
  	}
        else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
  	{
  	  result_type = type1;
  	  if (! flag_traditional)
  	    pedwarn ("comparison between pointer and integer");
+ 	  bounds_checked_comparison = 1;
  	}
        break;
      }
***************
*** 2601,2610 ****
    if (build_type == NULL_TREE)
      build_type = result_type;
  
    {
!     register tree result = build (resultcode, build_type, op0, op1);
      register tree folded;
  
      folded = fold (result);
      if (folded == result)
        TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
--- 2661,2677 ----
    if (build_type == NULL_TREE)
      build_type = result_type;
  
+   /* Build the final expression here. */
    {
!     register tree result;
      register tree folded;
  
+     if (!bounds_checking_enabled
+ 	|| bounds_in_static_decl
+ 	|| !bounds_checked_comparison)
+       result = build (resultcode, build_type, op0, op1);
+     else
+       result = bounds_build_comparison (resultcode, build_type, op0, op1);
      folded = fold (result);
      if (folded == result)
        TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
***************
*** 2615,2621 ****
  }
  
  /* Return a tree for the sum or difference (RESULTCODE says which)
!    of pointer PTROP and integer INTOP.  */
  
  static tree
  pointer_int_sum (resultcode, ptrop, intop)
--- 2682,2691 ----
  }
  
  /* Return a tree for the sum or difference (RESULTCODE says which)
!    of pointer PTROP and integer INTOP.
!    (RWMJ): If bounds-checking is switched on, generate a call to
!    __bounds_check_ptr_plus_int to check the operation.
!    */
  
  static tree
  pointer_int_sum (resultcode, ptrop, intop)
***************
*** 2646,2651 ****
--- 2716,2733 ----
    else
      size_exp = c_size_in_bytes (TREE_TYPE (result_type));
  
+   /* For bounds checked code, we have all the information necessary to
+    * generate the function call here. We generate the call
+    * __bounds_check_ptr_plus_int (void *pointer, int offset, size_t size,
+    *				  int is_plus, char *filename, int line);
+    * where pointer is the pointer value, offset is the int operand, size
+    * is the size_exp, is_plus is resultcode == PLUS_EXPR, etc.
+    */
+   if (bounds_checking_enabled
+       && !bounds_in_static_decl) {
+     return bounds_build_ptr_plus_int (resultcode, ptrop, intop, size_exp);
+   }
+ 
    /* If what we are about to multiply by the size of the elements
       contains a constant term, apply distributive law
       and multiply that constant term separately.
***************
*** 2721,2726 ****
--- 2803,2816 ----
  	pedwarn ("pointer to a function used in subtraction");
      }
  
+   if (bounds_checking_enabled && !bounds_in_static_decl) {
+     /* Build a call to the following function here instead:	(RWMJ)
+      *	   int	__bounds_check_ptr_diff (void *ptr1, void *ptr2, size_t size,
+      *					 char *filename, int line);
+      */
+     return bounds_build_ptr_diff (op0, op1, target_type);
+   }
+ 
    /* First do the subtraction as integers;
       then drop through to build the divide operator.  */
  
***************
*** 2827,2834 ****
  	  errstring = "wrong type argument to unary exclamation mark";
  	  break;
  	}
!       arg = truthvalue_conversion (arg);
!       return invert_truthvalue (arg);
  
      case NOP_EXPR:
        break;
--- 2917,2937 ----
  	  errstring = "wrong type argument to unary exclamation mark";
  	  break;
  	}
!       /* In bounds checking mode, if we are inverting a pointer (ie. `!ptr')
!        * we want to check that the pointer is not ILLEGAL and not pointing
!        * to invalid memory. -- RWMJ.
!        */
!       if (bounds_checking_enabled
! 	  && (typecode == POINTER_TYPE || typecode == ARRAY_TYPE
! 	      || typecode == FUNCTION_TYPE))
! 	{
! 	  return bounds_build_invert_truthvalue (arg);
! 	}
!       else
! 	{
! 	  arg = truthvalue_conversion (arg);
! 	  return invert_truthvalue (arg);
! 	}
  
      case NOP_EXPR:
        break;
***************
*** 2976,2982 ****
  			      || code == POSTINCREMENT_EXPR)
  			     ? "increment" : "decrement"));
  
! 	val = build (code, TREE_TYPE (arg), arg, inc);
  	TREE_SIDE_EFFECTS (val) = 1;
  	val = convert (result_type, val);
  	if (TREE_CODE (val) != code)
--- 3079,3098 ----
  			      || code == POSTINCREMENT_EXPR)
  			     ? "increment" : "decrement"));
  
! 	/* If bounds checking, generate a function call to ensure the inc/dec-
! 	 * rement will be correct.
! 	 * (RWMJ)
! 	 */
! 	if (bounds_checking_enabled && !bounds_in_static_decl
! 	    && typecode == POINTER_TYPE)
! 	  {
! 	    val = bounds_build_inc_or_dec (code, TREE_TYPE (arg), arg, inc);
! 	  }
! 	else
! 	  {
! 	    val = build (code, TREE_TYPE (arg), arg, inc);
! 	  }
! 
  	TREE_SIDE_EFFECTS (val) = 1;
  	val = convert (result_type, val);
  	if (TREE_CODE (val) != code)
***************
*** 2988,3009 ****
        /* Note that this operation never does default_conversion
  	 regardless of NOCONVERT.  */
  
!       /* Let &* cancel out to simplify resulting code.  */
!       if (TREE_CODE (arg) == INDIRECT_REF)
  	{
! 	  /* Don't let this be an lvalue.  */
! 	  if (lvalue_p (TREE_OPERAND (arg, 0)))
! 	    return non_lvalue (TREE_OPERAND (arg, 0));
! 	  return TREE_OPERAND (arg, 0);
! 	}
  
!       /* For &x[y], return x+y */
!       if (TREE_CODE (arg) == ARRAY_REF)
  	{
! 	  if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
! 	    return error_mark_node;
! 	  return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
! 				  TREE_OPERAND (arg, 1), 1);
  	}
  
        /* Handle complex lvalues (when permitted)
--- 3104,3140 ----
        /* Note that this operation never does default_conversion
  	 regardless of NOCONVERT.  */
  
!       if (!(bounds_checking_enabled && !bounds_in_static_decl))
  	{
! 	  /* Let &* cancel out to simplify resulting code.  */
! 	  if (TREE_CODE (arg) == INDIRECT_REF)
! 	    {
! 	      /* Don't let this be an lvalue.  */
! 	      if (lvalue_p (TREE_OPERAND (arg, 0)))
! 		return non_lvalue (TREE_OPERAND (arg, 0));
! 	      return TREE_OPERAND (arg, 0);
! 	    }
  
! 	  /* For &x[y], return x+y */
! 	  if (TREE_CODE (arg) == ARRAY_REF)
! 	    {
! 	      if (mark_addressable (TREE_OPERAND (arg, 0)) == 0)
! 		return error_mark_node;
! 	      return build_binary_op (PLUS_EXPR, TREE_OPERAND (arg, 0),
! 				      TREE_OPERAND (arg, 1), 1);
! 	    }
! 	}
!       else
  	{
! 	  /* In bounds checking code, the patterns for '&*' and '&x[y]' are
! 	   * more complicated because we have already expanded the '*' or the
! 	   * 'x[y]' expression. We sort this out in 'c-bounds.c' (RWMJ).
! 	   */
! 	  tree cancelled_expr
! 	    = bounds_cancel_address_expr (arg);
! 
! 	  if (cancelled_expr != NULL_TREE)
! 	    return cancelled_expr;
  	}
  
        /* Handle complex lvalues (when permitted)
***************
*** 5099,5104 ****
--- 5230,5240 ----
      = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
    char *asmspec = 0;
  
+   /* In a static initializer, temporarily turn off bounds checking.
+    */
+   if (bounds_checking_enabled && decl != 0)
+     bounds_in_static_decl = TREE_STATIC (decl);
+ 
    if (asmspec_tree)
      asmspec = TREE_STRING_POINTER (asmspec_tree);
  
***************
*** 5118,5124 ****
    initializer_stack = p;
  
    constructor_decl = decl;
!   constructor_incremental = top_level;
    constructor_asmspec = asmspec;
    constructor_subconstants_deferred = 0;
    constructor_top_level = top_level;
--- 5254,5260 ----
    initializer_stack = p;
  
    constructor_decl = decl;
!   constructor_incremental = top_level && !bounds_checking_enabled; /* RWMJ */
    constructor_asmspec = asmspec;
    constructor_subconstants_deferred = 0;
    constructor_top_level = top_level;
***************
*** 5135,5141 ****
  	       || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
  	       || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
        locus = IDENTIFIER_POINTER (DECL_NAME (decl));
!       constructor_incremental |= TREE_STATIC (decl);
      }
    else
      {
--- 5271,5278 ----
  	       || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
  	       || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
        locus = IDENTIFIER_POINTER (DECL_NAME (decl));
!       constructor_incremental |= TREE_STATIC (decl)
! 	&& !bounds_checking_enabled; /* RWMJ */
      }
    else
      {
***************
*** 5190,5195 ****
--- 5327,5338 ----
    constructor_top_level = p->top_level;
    initializer_stack = p->next;
    free (p);
+ 
+   /* If bounds checking was temporarily suspended in a static decl, turn it
+    * back on.
+    */
+   if (bounds_checking_enabled)
+     bounds_in_static_decl = 0;
  }
  
  /* Call here when we see the initializer is surrounded by braces.
*** gcc-2.7.2-orig/calls.c	Thu Nov 16 00:54:48 1995
--- gcc-2.7.2/calls.c	Thu Nov 16 16:37:17 1995
***************
*** 30,35 ****
--- 30,37 ----
  #endif
  #include "insn-flags.h"
  
+ #include "c-bounds.h"
+ 
  /* Decide whether a function's arguments should be processed
     from first to last or from last to first.
  
***************
*** 126,132 ****
  static int calls_function	PROTO((tree, int));
  static int calls_function_1	PROTO((tree, int));
  static void emit_call_1		PROTO((rtx, tree, tree, int, int, rtx, rtx,
! 				       int, rtx, int));
  static void store_one_arg	PROTO ((struct arg_data *, rtx, int, int,
  					tree, int));
  
--- 128,134 ----
  static int calls_function	PROTO((tree, int));
  static int calls_function_1	PROTO((tree, int));
  static void emit_call_1		PROTO((rtx, tree, tree, int, int, rtx, rtx,
! 				       int, rtx, int, int));
  static void store_one_arg	PROTO ((struct arg_data *, rtx, int, int,
  					tree, int));
  
***************
*** 341,347 ****
  static void
  emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size, 
               next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
! 	     is_const)
       rtx funexp;
       tree fndecl;
       tree funtype;
--- 343,349 ----
  static void
  emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size, 
               next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
! 	     is_const, is_bounds_libcall)
       rtx funexp;
       tree fndecl;
       tree funtype;
***************
*** 352,357 ****
--- 354,360 ----
       int old_inhibit_defer_pop;
       rtx call_fusage;
       int is_const;
+      int is_bounds_libcall;
  {
    rtx stack_size_rtx = GEN_INT (stack_size);
    rtx struct_value_size_rtx = GEN_INT (struct_value_size);
***************
*** 461,467 ****
  
    if (stack_size != 0)
      {
!       if (flag_defer_pop && inhibit_defer_pop == 0 && !is_const)
  	pending_stack_adjust += stack_size;
        else
  	adjust_stack (stack_size_rtx);
--- 464,471 ----
  
    if (stack_size != 0)
      {
!       if (flag_defer_pop && inhibit_defer_pop == 0 &&
! 	  !is_const && !is_bounds_libcall)
  	pending_stack_adjust += stack_size;
        else
  	adjust_stack (stack_size_rtx);
***************
*** 574,579 ****
--- 578,591 ----
    int is_const = 0;
    /* Nonzero if this is a call to a `volatile' function.  */
    int is_volatile = 0;
+ 
+   /* Nonzero if this is a call to '__bounds_add_param_object', '__bounds_add_
+    * stack_object', '__bounds_delete_stack_object', '__bounds_push_function'
+    * or '__bounds_pop_function' and we are in bounds checking mode. In that
+    * case, we may delete the call later in `bounds_delete_redundant_calls'.
+    */
+   int is_bounds_libcall = 0;
+ 
  #if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
    /* Define the boundary of the register parm stack space that needs to be
       save, if any.  */
***************
*** 806,820 ****
        mark_addressable (fndecl);
      }
  
!   /* When calling a const function, we must pop the stack args right away,
!      so that the pop is deleted or moved with the call.  */
!   if (is_const)
!     NO_DEFER_POP;
  
    function_call_count++;
  
!   if (fndecl && DECL_NAME (fndecl))
!     name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
  
    /* On some machines (such as the PA) indirect calls have a different
       calling convention than normal calls.  FUNCTION_ARG in the target
--- 818,839 ----
        mark_addressable (fndecl);
      }
  
!   if (fndecl && DECL_NAME (fndecl))
!     name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
  
    function_call_count++;
  
!   /* If this is a call to the bounds checking library, we may delete it
!    * later. Make this clear here.
!    */
!   if (bounds_checking_enabled &&
!       bounds_is_deletable_fn_p (name))
!     is_bounds_libcall = 1;
! 
!   /* When calling a const function, we must pop the stack args right away,
!      so that the pop is deleted or moved with the call.  */
!   if (is_const || is_bounds_libcall)
!     NO_DEFER_POP;
  
    /* On some machines (such as the PA) indirect calls have a different
       calling convention than normal calls.  FUNCTION_ARG in the target
***************
*** 1362,1368 ****
  
    /* Now we are about to start emitting insns that can be deleted
       if a libcall is deleted.  */
!   if (is_const)
      start_sequence ();
  
    /* If we have no actual push instructions, or shouldn't use them,
--- 1381,1387 ----
  
    /* Now we are about to start emitting insns that can be deleted
       if a libcall is deleted.  */
!   if (is_const || is_bounds_libcall)
      start_sequence ();
  
    /* If we have no actual push instructions, or shouldn't use them,
***************
*** 1914,1920 ****
    /* Generate the actual call instruction.  */
    emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size,
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
! 	       valreg, old_inhibit_defer_pop, call_fusage, is_const);
  
    /* If call is cse'able, make appropriate pair of reg-notes around it.
       Test valreg so we don't crash; may safely ignore `const'
--- 1933,1940 ----
    /* Generate the actual call instruction.  */
    emit_call_1 (funexp, fndecl, funtype, args_size.constant, struct_value_size,
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
! 	       valreg, old_inhibit_defer_pop, call_fusage, is_const,
! 	       is_bounds_libcall);
  
    /* If call is cse'able, make appropriate pair of reg-notes around it.
       Test valreg so we don't crash; may safely ignore `const'
***************
*** 1943,1948 ****
--- 1963,1985 ----
  
        valreg = temp;
      }
+   else if (is_bounds_libcall)
+     {
+       /* In bounds checking mode, if this is one of the calls we may delete
+        * later, then mark this list of insns in our private list so that
+        * we may delete them later.		(RWMJ)
+        */
+       rtx insns = get_insns ();
+       rtx first_in_call, last_in_call;
+ 
+       first_in_call = insns;
+       last_in_call = get_last_insn ();
+       end_sequence ();
+       emit_insns (insns);
+ 
+       bounds_note_call_for_deletion (first_in_call, last_in_call,
+ 				     name, exp);
+     }
    else if (is_const)
      {
        /* Otherwise, just write out the sequence without a note.  */
***************
*** 2494,2500 ****
                 get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
  	       outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
! 	       old_inhibit_defer_pop + 1, call_fusage, no_queue);
  
    pop_temp_slots ();
  
--- 2531,2537 ----
                 get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
  	       outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
! 	       old_inhibit_defer_pop + 1, call_fusage, no_queue, 0);
  
    pop_temp_slots ();
  
***************
*** 2859,2865 ****
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
  	       (outmode != VOIDmode && mem_value == 0
  		? hard_libcall_value (outmode) : NULL_RTX),
! 	       old_inhibit_defer_pop + 1, call_fusage, is_const);
  
    /* Now restore inhibit_defer_pop to its actual original value.  */
    OK_DEFER_POP;
--- 2896,2902 ----
  	       FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
  	       (outmode != VOIDmode && mem_value == 0
  		? hard_libcall_value (outmode) : NULL_RTX),
! 	       old_inhibit_defer_pop + 1, call_fusage, is_const, 0);
  
    /* Now restore inhibit_defer_pop to its actual original value.  */
    OK_DEFER_POP;
*** gcc-2.7.2-orig/extend.texi	Thu Nov 16 00:56:49 1995
--- gcc-2.7.2/extend.texi	Tue Jan 16 23:33:48 1996
***************
*** 62,67 ****
--- 62,69 ----
  * Incomplete Enums::    @code{enum foo;}, with details to follow.
  * Function Names::	Printable strings which are the name of the current
  			 function.
+ * Bounds Checking::     Add full, fine-grained array & pointer checking to
+                          C programs.
  @end menu
  @end ifset
  @ifclear INTERNALS
***************
*** 107,112 ****
--- 109,116 ----
  * Incomplete Enums::    @code{enum foo;}, with details to follow.
  * Function Names::	Printable strings which are the name of the current
  			 function.
+ * Bounds Checking::     Add full, fine-grained array & pointer checking to
+                          C programs.
  @end menu
  @end ifclear
  
***************
*** 2630,2635 ****
--- 2634,3309 ----
  For example, @samp{#ifdef __FUNCTION__} does not have any special
  meaning inside a function, since the preprocessor does not do anything
  special with the identifier @code{__FUNCTION__}.
+ 
+ @node Bounds Checking
+ @section Bounds Checking
+ @cindex Bounds Checking
+ 
+ The C part of the GNU compiler now supports full fine-grained pointer checking
+ at runtime. This work was originally done by @w{Richard W.M. Jones}
+ <rwmj@@doc.ic.ac.uk>,
+ and has been extended by the work of many other kind
+ contributors.@footnote{See the file @file{bounds/CONTRIBUTORS} for a full
+ list of the people who gave their effort for free to make all this possible.}
+ 
+ The runtime checking library, test kit and various tools can be found in
+ the @file{bounds/} subdirectory.
+ 
+ The brief manual here is a distillation of the original paper that appeared
+ at the same time as the original patches to GCC. The paper contains more
+ details about the inner workings of bounds checking GCC. The paper can be
+ found in PostScript format in @file{bounds/report/bcrep2.ps.gz}.
+ 
+ @menu
+ * Compiling with checks::       How to compile your programs with bounds
+                                  checks on at runtime.
+ * Incompatibilities with checking:: You can't use setjmp/longjmp, and threads
+                                  and signal handlers need special attention.
+ * Unchecked code and libraries:: You can freely mix unchecked source files and
+                                  libraries with your checked program.
+ * Debugging with GDB::          You may debug bounds checked programs with
+                                  GDB and there are special breakpoints for this
+                                  purpose.
+ * Environment at runtime::      Customizing the runtime environment by passing
+                                  options in @code{GCC_BOUNDS_OPTS}.
+ * Managing the heap::           How bounds checking uses the heap at runtime.
+ * Unchecked objects::           How unchecked objects work.
+ * Miscellaneous features::      Other features that might be of interest.
+ * Checking 2D array indices::   Notes about 2D array indices.
+ * What errors are caught::      What errors are caught and what errors are
+                                  missed?
+ * Performance::                 How fast (or slow) can you expect bounds
+                                  checked programs to go?
+ * Stubborn bugs::               Special ``features'' you may need to know
+                                  about.
+ * Using G77 with bounds checking:: A small patch you have to make to get a
+                                 smooth compile with G77.
+ @end menu
+ 
+ @ignore
+ 
+ NOT YET DOCUMENTED!!! ---
+ 
+ bounds/tools subdirectory
+ bounds/misc subdirectory
+ bounds/report subdirectory
+ bounds/tests subdirectory
+ bounds/treestats subdirectory
+ 
+ tidy up this menu - need to make it more hierarchical
+ 
+ @end ignore
+ 
+ @node Compiling with checks
+ @subsection Compiling with checks
+ 
+ To compile all or part of your program with bounds checking, simply add the
+ @code{-fbounds-checking} flag when compiling and linking. In the simplest
+ instance, you might do:
+ 
+ @example
+ gcc -fbounds-checking program.c -o program
+ @end example
+ 
+ @noindent
+ Or, linking several checked files together:
+ 
+ @example
+ gcc -fbounds-checking -c file1.c -o file1.o
+ gcc -fbounds-checking -c file2.c -o file2.o
+ gcc -fbounds-checking -c file3.c -o file3.o
+ gcc -fbounds-checking file1.o file2.o file3.o -o program
+ @end example
+ 
+ If your program uses a Makefile, you will probably only need to add the
+ @code{-fbounds-checking} flag to @code{CFLAGS}, and remake the program
+ from scratch.
+ 
+ @node Incompatibilities with checking
+ @subsection Incompatibilities with checking
+ 
+ @itemize @bullet
+ @item Programs that use setjmp and longjmp.
+ 
+ Bounds checking is unfortunately incompatible with setjmp/longjmp. This is
+ regrettable, but the problem is quite fundamental and it is unlikely that
+ these functions will ever be permissable.
+ 
+ @item Using signal handlers.
+ 
+ If possible, move signal handlers to a separate source file and set checking
+ off in that file. If this is not possible, then you will need to edit
+ @file{bounds/lib/mutex.h} which provides mutual exclusion to vital
+ internal structures in the checking library. Normally this mutual exclusion
+ is turned off, for reasons of efficiency.
+ 
+ @item Using threads.
+ 
+ You may use threads with bounds checking. If more than one thread could
+ ever run with bounds checking, you will need to provide mutual exclusion
+ as with signal handlers above. Edit the file @file{bounds/lib/mutex.h} and
+ add whatever code is necessary to give mutual exclusion.
+ 
+ @item Checking C++ programs.
+ 
+ Every so often, someone mails me to ask why their C++ program isn't checked
+ when they do @code{g++ -fbounds-checking}. At the moment, the bounds checking
+ changes are specific to the C front end, so you can't use them with the other
+ GCC front ends (eg. C++, FORTRAN, Modula-2). There is no reason why bounds
+ checking couldn't be added to the C++ front end. It would take perhaps one or
+ two months to do. It is highly unlikely that I will ever do this, but if a
+ keen beta-tester wants it enough, I may be willing to help them. In the
+ meantime, it is possible to translate C++ programs to C and check them, but
+ line number and other debugging information may get scrambled in the process.
+ @end itemize
+ 
+ 
+ @node Unchecked code and libraries
+ @subsection Unchecked code and libraries
+ 
+ You can normally freely mix unchecked and checked code. This is why you don't
+ need to make any changes to your C or X11 libraries when you install GCC
+ with bounds checking. The checking library will detect code compiled with
+ and without checking automagically, and let the two run together. You
+ can mix unchecked object files with checked ones for the same reason. Always
+ pass the @code{-fbounds-checking} flag to the link stage.
+ 
+ @example
+ gcc -fbounds-checking -c file1.c -o file1.o
+ gcc -c unchecked.c -o unchecked.o
+ gcc -fbounds-checking file1.o unchecked.o -o program
+ @end example
+ 
+ The checking library will usually only know about variables that are
+ declared in checked code, and about memory allocated with @code{malloc}. So
+ if a variable is declared in @file{unchecked.c} above, then references
+ to it will @emph{not} be checked, even when these references occur in
+ checked code.
+ 
+ Say that file @file{unchecked.c} contains the following code:
+ 
+ @example
+ int a[10];
+ 
+ int *get_ptr_to_a () @{ return a; @}
+ @end example
+ 
+ and file @file{file1.c} contains:
+ 
+ @example
+ extern int *get_ptr_to_a ();
+ 
+ main ()
+ @{
+   int *ptr_to_a = get_ptr_to_a ();
+   int i;
+ 
+   for (i = 0; i < 20; ++i) ptr_to_a[i] = 0;
+ @}
+ @end example
+ 
+ The references to @code{ptr_to_a} will not be checked. You can resolve
+ this by adding @code{a}, either by hand, or semi-automatically.
+ @xref{Unchecked objects}
+ 
+ If you place @code{extern int a[10];} anywhere in @file{file1.c}, bounds
+ checking GCC will also be able to find and check the array references
+ properly.
+ 
+ If you include @file{bounds/run-includes/unchecked.h}, you get facilities
+ to turn bounds checking on and off over short stretches of code and
+ within single expressions and statements. Even when bounds checking is
+ switched off, you may still use these features. The macros are silently
+ ignored if bounds checking is off, or if the compiler is not GCC.
+ 
+ @itemize @bullet
+ @item @code{BOUNDS_CHECKING_OFF} @dots{} @code{BOUNDS_CHECKING_ON}
+ 
+ Turn off bounds checking over a section of code. For instance:
+ @example
+ /* This code is checked ... */
+ BOUNDS_CHECKING_OFF;
+ /* This code is unchecked ... */
+ BOUNDS_CHECKING_ON;
+ /* This code is checked again ... */
+ @end example
+ The unchecked code should not try to return from a function, or jump over
+ the @code{BOUNDS_CHECKING_ON} statement with @code{goto}, else checking
+ will be switched off for the rest of the program!
+ 
+ @item @code{BOUNDS_CHECKING_OFF_DURING}
+ 
+ Switch off checking in a single statement. For instance:
+ @example
+ BOUNDS_CHECKING_OFF_DURING (p += 5);
+ @end example
+ The statement should not (obviously) be goto, return, @dots{}
+ 
+ @item @code{BOUNDS_CHECKING_OFF_IN_EXPR}
+ 
+ Switch off checking while a single expression is being evaluated. For instance:
+ @example
+ p = BOUNDS_CHECKING_OFF_IN_EXPR (a + 5);
+ @end example
+ 
+ @end itemize
+ 
+ @node Debugging with GDB
+ @subsection Debugging with GDB
+ 
+ If you have GDB (or another debugger) on your system, you will be able to
+ debug bounds checked programs easily and efficiently. To help you catch
+ bounds errors before the program aborts (which sometimes causes the
+ program's stack to disappear), place a breakpoint at
+ @code{__bounds_breakpoint}. The checking library always calls this
+ breakpoint before aborting. If the @code{-never-fatal} flag has been supplied
+ @xref{Environment at runtime}, you will need to place this
+ breakpoint, since the program does not abort when it hits a bounds error.
+ 
+ @node Environment at runtime
+ @subsection Environment at runtime
+ 
+ You can customize the way a bounds-checked program runs by passing options
+ to it in the environment variable `GCC_BOUNDS_OPTS'. For instance, suppose
+ you don't want the banner message that appears when bounds checked programs
+ start up. With sh or ksh, you might type:
+ 
+ @example
+ % GCC_BOUNDS_OPTS='-no-message' program
+ @end example
+ 
+ With csh:
+ 
+ @example
+ % setenv GCC_BOUNDS_OPTS '-no-message'; program
+ @end example
+ 
+ You can put any combination of the following flags in GCC_BOUNDS_OPTS. Place
+ spaces or tabs between each flag.
+ 
+ @table @samp
+ @item -no-message
+ Don't print the introductory message.
+ @item -no-statistics
+ Don't print library call statistics with the program quits.
+ @item -?, -help
+ Print this list of options, then quit the program before it starts.
+ @item -reuse-heap (*)
+ @item -reuse-age=<age>
+ @item -no-reuse-heap
+ See the discussion of heap memory, @xref{Managing the heap}.
+ @item -warn-unchecked-statics
+ @item -no-warn-unchecked-statics (*)
+ @item -warn-unchecked-stack
+ @item -no-warn-unchecked-stack (*)
+ See the discussion of unchecked objects, @xref{Unchecked objects}.
+ @item -warn-free-null (*)
+ @item -no-warn-free-null
+ Give a warning if free (0) is called. Note that this may be correct in
+ ANSI C, and some libraries, notably X11, do it quite often.
+ @item -warn-misc-strings (*)
+ @item -no-warn-misc-strings
+ Miscellaneous warnings with str* and mem* functions, such as trying to call
+ @code{memcpy} with size = 0.
+ @item -warn-illegal
+ @item -no-warn-illegal (*)
+ Warn when ILLEGAL pointers are generated. These patches, provided by
+ @w{Don Lewis} <gdonl@@gv.ssi1.com>, help to track down ILLEGAL pointer
+ errors when they happen.
+ @item -warn-unaligned (*)
+ @item -no-warn-unaligned
+ Warn when a pointer is used in an unaligned manner, for instance reading
+ integer data as chars. This warning is turned on by default, but may be
+ disabled, since some programs do this quite harmlessly. These patches were
+ suggested by @w{Stuart Kemp} and @w{Eberhard Mattes}.
+ @item -warn-all
+ Turn on all of the warnings above.
+ @item -array-index-check
+ @item -no-array-index-check (*)
+ Check 2D array indices correctly. This is turned off by default, since it
+ causes incompatibilities with perfectly correct programs.
+ @xref{Checking 2D array indices}
+ @item -never-fatal
+ Normally the library will call abort() after it detects the first bounds
+ error. If this flag is given, the library attempts to proceed. The first
+ error may generate more errors itself afterwards, so only the first error
+ is guaranteed to be correct.
+ @item -print-calls
+ @item -no-print-calls (*)
+ Print calls to the checking library. This option is only useful if you
+ want to debug bounds checking GCC itself.
+ @end table
+ 
+ Items marked with a `(*)' are the default.
+ 
+ @node Managing the heap
+ @subsection Managing the heap
+ 
+ The bounds checking library includes a customized version of the GNU
+ @code{malloc} library. Calls to @code{malloc}, @code{free}, @code{realloc},
+ @code{calloc}, @code{cfree}, @code{valloc} and @code{memalign} are
+ checked. You will get a bounds error if you try to:
+ 
+ @itemize @bullet
+ @item
+ Free a pointer that has not been allocated in the proper way, or free a pointer
+ twice.
+ 
+ @item
+ Reallocate a pointer that has not been allocated, or has been freed.
+ 
+ @item
+ Use a pointer to freed memory, or to memory that has been moved by
+ @code{realloc}.
+ 
+ @item
+ Free or reallocate static memory.
+ 
+ @end itemize
+ 
+ Bounds checking GCC does not attempt to detect memory leaks, nor is it
+ capable of garbage collection.
+ 
+ There are several strategies for tracking stale memory pointers. Ideally,
+ we would like to never reuse VM after the programmer has freed it, so that
+ we will always be able to detect a stale pointer, no matter how long the
+ program runs before using it. If you wish this behaviour, then pass
+ the @code{-no-reuse-heap} option in `GCC_BOUNDS_OPTS'
+ @xref{Environment at runtime}.@footnote{In a future version of bounds
+ checking GCC, we will be able to unmap this memory. Thus the operating
+ system will be able to reuse physical memory, whilest virtual memory
+ addresses remain unused.}
+ 
+ In practice, we found this technique to be wasteful, so the default is to
+ reuse heap memory immediately. However, in order to provide some
+ protection against stale pointers, you may pass the @code{-reuse-age=<age>}
+ option to the library. This will add freed blocks to a queue of pending
+ blocks. You must call @code{free} @code{<age>} times before the block
+ is actually reused.
+ 
+ Notice that the most common error is:
+ 
+ @example
+ free_list (list *p)
+ @{
+   for (; p != NULL; p = p->next)
+     free (p);
+ @}
+ @end example
+ 
+ The default flags, @code{-reuse-heap -reuse-age=0}, will catch this error.
+ 
+ @node Unchecked objects
+ @subsection Unchecked objects
+ 
+ Variables declared in files that are not compiled with @code{-fbounds-checking}
+ are not normally known about by the checking library. Pointers that
+ point to these variables are not checked, even where the operations
+ on these pointers happen within checked code. To be sure that your
+ program is running without any errors, you should turn on warnings about
+ unchecked operations by giving the @code{-warn-unchecked-statics} and/or
+ @code{-warn-unchecked-stack} flags at runtime. @xref{Environment at
+ runtime}.
+ 
+ To avoid these warnings, and check all operations, you should take steps
+ to add these objects to the tree used by the checking library. There are
+ three approaches:
+ 
+ @itemize @bullet
+ @item
+ Declare the object as @code{extern} somewhere in checked code. Make sure that
+ the size of the object appears in the expression, ie. @code{extern int a[10];},
+ not @code{extern int a[];}.
+ 
+ @item
+ Add the object by hand by calling @code{__bounds_note_constructed_object}.
+ This function is declared:
+ @example
+ void __bounds_note_constructed_object (ptr, size, align, filename, line, name);
+   void *ptr;      /* Pointer to the object. */
+   size_t size;    /* Size of the object (bytes). */
+   size_t align;   /* Pass 1 here. */
+   char *filename; /* Filename where declared (for debugging). */
+   int line;       /* Line number. */
+   char *name;     /* Name of the object. */
+ @end example
+ 
+ @item
+ Add all the objects from a single object file, or a library automagically,
+ using the @code{grab-statics} tool in @file{bounds/tools}. There is a README
+ file in that directory that will tell you more.
+ 
+ @end itemize
+ 
+ @node Miscellaneous features
+ @subsection Miscellaneous features
+ 
+ @itemize @bullet
+ @item Detecting when a source file is being compiled with bounds checking.
+ 
+ When GCC compiles a file with the @code{-fbounds-checking} flag, it
+ defines @code{__BOUNDS_CHECKING_ON} in the preprocessor. In addition, the
+ variable @code{__bounds_checking_on} is set to 1 when bounds checking is
+ on in the program as a whole, and set to 0 when it is not. The variable
+ is actually located in @code{libgcc.a}, so it is always present (unless
+ you aren't using GCC).
+ 
+ Notice the subtle difference between these two methods. Say a program
+ consists of source files @file{file1.c} and @file{file2.c}. If the
+ program is compiled with
+ 
+ @example
+ gcc -fbounds-checking -c file1.c
+ gcc -c file2.c
+ gcc -fbounds-checking file1.o file2.o -o program
+ @end example
+ 
+ @noindent
+ then @file{file1.c} will be compiled with @code{__BOUNDS_CHECKING_ON}
+ defined. In @file{file2.c} this will not be defined. Both files will
+ be able to declare @code{extern int __bounds_checking_on;} and the
+ variable will be read as @code{1} by both.
+ 
+ If the same files are compiled without bounds checking, then
+ @code{__BOUNDS_CHECKING_ON} will not be defined. Both files will be
+ able to declare @code{extern int __bounds_checking_on;} and will read
+ the variable as @code{0}.
+ 
+ If the same files are compiled with another C compiler, then variable
+ @code{__bounds_checking_on} will not exist. So all references to this
+ variable should be defended by @code{#ifdef __GNUC__} @dots{}
+ @code{#endif}.
+ 
+ @end itemize
+ 
+ @node Checking 2D array indices
+ @subsection Checking 2D array indices
+ 
+ 2D arrays (and, indeed, n-D arrays with n >= 2) are not checked as you might
+ expect. We consider such arrays to be flattened before checking. For instance
+ a mathematical 3x3-matrix @code{A} might be defined as:
+ 
+ @example
+ double A[3][3];
+ @end example
+ 
+ Bounds checking will normally consider this to be a flat array with 9 elements.
+ So, it is perfectly sound to write @code{A[1][4]}, since @code{1*3+4} @equiv{}
+ @code{7}, and 0 <= 7 < 9. Similarly, @code{A[0][8]} and @code{A[2][-1]}
+ will not generate bounds errors. (Interestingly, though, errors in the
+ first index @emph{will} be caught --- this is to do with a subtlety in the
+ way bounds checking works).
+ 
+ This is really down to the way that bounds checking works. Bounds checking
+ loses a lot of information about the internal structure of objects, storing
+ essentially just the start and size of the object. In future, we hope to
+ store more information. In the example above, we would store the fact that
+ @code{A} is a 3x3 array of doubles. This will allow us to check indices
+ correctly.
+ 
+ In the meantime, Herman ten Brugge has written a partial solution for 2D
+ arrays. It will flag errors like the examples I gave above. You can get
+ this behaviour by supplying @code{-array-index-check} in
+ @code{GCC_BOUNDS_OPTS}.
+ 
+ Herman's fixes unfortunately break other correct C usage, in particular,
+ the common form:
+ 
+ @example
+ struct _string_t
+ @{
+   int len;
+   char str[1];
+ @};
+ @end example
+ 
+ @noindent
+ (where the structure is allocated with extra bytes for the string). Because
+ this is quite common in C, I have turned Herman's patch off by default.
+ 
+ @node What errors are caught
+ @subsection What errors are caught
+ 
+ A lot of people tell me that they have Purify, and bounds checking GCC seems
+ unnecessary, since it seems to duplicate Purify but more slowly. Well,
+ there are important reasons why bounds checking GCC is better than Purify,
+ and if you rely on Purify alone, you will certainly miss bugs in your
+ program.
+ 
+ @noindent
+ This is what bounds checking GCC will find, which Purify won't:
+ 
+ @itemize @bullet
+ @item Bounds of stack and static variables
+ 
+ Try compiling:
+ @example
+ main ()
+ @{
+   int a[10], b[100], i;
+ 
+   for (i = 0; i < 100; ++i)
+     a[i] = 0;
+ @}
+ @end example
+ Purify will only detect these sorts of errors reliably if @code{a} is allocated
+ with @code{malloc}.
+ 
+ @item Large offsets from memory allocated with @code{malloc}
+ 
+ Bugs such as the following one will not be found reliably by Purify, since
+ it only puts a certain amount of blank padding between @code{malloc}'d
+ memory.
+ @example
+ struct large_type @{
+   int data[5000];
+ @};
+ 
+ main ()
+ @{
+   char *m1;
+   struct large_type *m2;
+   int i;
+ 
+   m1 = (char *) malloc (20000);
+   m2 = (struct large_type *) malloc (sizeof (struct large_type) * 5);
+ 
+   for (i = 4; i >= -2; --i) /* note: error when i == -1 */
+     m2[i].data[0] = 0;
+ @}
+ @end example
+ 
+ @end itemize
+ 
+ @noindent
+ This is what Purify will find, which bounds checking GCC won't:
+ 
+ @itemize @bullet
+ @item Using a variable or memory before it is initialized
+ 
+ Bounds checking GCC can't currently check this, but it may well be added
+ in a future version. GCC itself will pick up simple instances of this
+ if you pass the @code{-Winitialized} flag (without @code{-fbounds-checking}),
+ but cannot check use of @code{malloc}'d memory.
+ 
+ @end itemize
+ 
+ There is a freeware program which emulates Purify available from Tristan
+ Gingold <gingold@@amoco.saclay.cea.fr>. It only runs under Linux. Purify
+ only works on Sun SPARCstations and HP-PA machines, and, of course, costs
+ lots of cash.
+ 
+ @node Performance
+ @subsection Performance
+ 
+ This page is under construction.
+ 
+ @node Stubborn bugs
+ @subsection Stubborn bugs
+ 
+ The very latest list of bugs can be found in @file{bounds/BUGS}. This is a
+ list of some of the most stubborn bugs, some of which have been around since
+ the first version. Please send bug reports and (even better) bug fixes to
+ `rwmj@@doc.ic.ac.uk'.
+ 
+ @itemize @bullet
+ @ignore
+ @item Incorrect initialization of arrays and structures.
+ 
+ Bounds checking relies on being able to rewrite initializers for stack
+ variables with side effect calls, so we can detect when a variable comes
+ into scope. For instance, the code:
+ 
+ @example
+ f ()
+ @{
+   @{
+     int a;
+     /* ... */
+   @}
+   @{
+     int b;
+     /* ... */
+   @}
+ @}
+ @end example
+ 
+ @noindent
+ may be rewritten as:
+ 
+ @example
+ f ()
+ @{
+   @{
+     int a = (__bounds_add_stack_object (&a, 4, 1, ...), 0);
+     /* ... */
+   @}
+   @{
+     int b = (__bounds_add_stack_object (&b, 4, 1, ...), 0);
+     /* ... */
+   @}
+ @}
+ @end example
+ 
+ The code that rewrites variable initializers is
+ @w{@code{c-bounds.c:bounds_frig_decl_initial}}. The function works for
+ simple things like basic types, strings, arrays of strings; but it chokes
+ on some more complicated types. It usually throws the error
+ 
+ @example
+ empty initializer cannot be bounds checked
+ @end example
+ 
+ @noindent
+ when it meets one of these usages. The following uses are known to throw
+ up this error (all occurring as auto variables inside functions):
+ 
+ @example
+ char nodes[][20] = @{"foo", "bar"@};
+ --- reported by Stuart Kemp <skemp@@bmc.com>
+ 
+ struct @{ unsigned char c[6]; @} e = @{ 1, 2, 3, 4, 5, 6 @};
+ 
+ struct @{ int foo, bar; @} var = *othervar;
+ --- reported by Frank Cringle <fdc@@cliwe.ping.de>
+ @end example
+ 
+ I don't fully understand the TREE generated by GCC for constructors. Can
+ someone else solve this?
+ @end ignore
+ 
+ @item Padding missed out between aggregates and 32-bit objects on the stack.
+ 
+ Bounds checking GCC usually inserts bytes of padding between adjacent
+ stack objects. This dead area between objects helps the checking library
+ to detect the difference between a pointer to the last byte + 1 of one
+ object and a pointer to the first byte of the next object. For some
+ reason, this padding is omitted occasionally when a 32-bit object (eg. int,
+ pointer) follows an aggregate (eg. array). But not always.
+ 
+ The bug used to happen under Linux, but at some point in the past it seems
+ to have fixed itself. The bug still appears under Solaris. You can demonstrate
+ the bug by compiling Tcl/Tk on Solaris. The checking library will report
+ at run time that a reference has been made to the byte following the end
+ of the first object. When you look at the code, you will see that it is in fact
+ referring to the next object (ie. the 32-bit integer).
+ 
+ Update (16/10/95): I fixed some stuff in @w{assign_stack_local} and
+ @w{assign_outer_stack_local} (thanks to @w{Don Lewis} @w{<gdonl@@gv.ssi1.com>})
+ but I haven't been able to verify that this bug has gone for sure.
+ 
+ @end itemize
+ 
+ @node Using G77 with bounds checking
+ @subsection Using G77 with bounds checking
+ 
+ Bounds checking patches break the current G77 patches. You can get round this
+ very easily. Copy @code{cp/bounds.c} into the @code{f/} subdirectory. Alter
+ @code{f/Makefile.in} so that it compiles @code{bounds.c} along with
+ the other G77 object files.
+ 
+ Notice that this doesn't add bounds checking to FORTRAN @w{(:-<)}. Just lets
+ you compile it.
  
  @node C++ Extensions
  @chapter Extensions to the C++ Language
*** gcc-2.7.2-orig/flags.h	Thu Jun 15 07:34:11 1995
--- gcc-2.7.2/flags.h	Tue Jul  4 10:59:17 1995
***************
*** 361,363 ****
--- 361,367 ----
     function.  */
  
  extern int current_function_has_nonlocal_goto;
+ 
+ /* Flag indicating bounds checking in the C front-end. (RWMJ). */
+ 
+ extern int bounds_checking_enabled;
*** gcc-2.7.2-orig/fold-const.c	Thu Nov 16 00:56:56 1995
--- gcc-2.7.2/fold-const.c	Thu Nov 16 16:40:02 1995
***************
*** 2098,2103 ****
--- 2098,2114 ----
      case CLEANUP_POINT_EXPR:
        return build1 (CLEANUP_POINT_EXPR, type,
  		     invert_truthvalue (TREE_OPERAND (arg, 0)));
+ 
+       /* (RWMJ, 5/3/95)
+        * Bounds checking often builds call expressions returning an integer
+        * in place of equality and inequality operations, so we must catch
+        * this case specially here. Otherwise, we abort after this switch
+        * statement, since the return type cannot be `BOOLEAN' in C.
+        */
+     case CALL_EXPR:
+       if (bounds_checking_enabled && TREE_CODE (type) == INTEGER_TYPE)
+ 	return build1 (TRUTH_NOT_EXPR, type, arg);
+       break;
      }
    if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE)
      abort ();
*** gcc-2.7.2-orig/function.c	Tue Dec  5 21:24:21 1995
--- gcc-2.7.2/function.c	Tue Dec  5 21:29:58 1995
***************
*** 702,707 ****
--- 702,710 ----
    if (BYTES_BIG_ENDIAN && mode != BLKmode)
      bigend_correction = size - GET_MODE_SIZE (mode);
  
+   if (bounds_checking_enabled)	/* RWMJ */
+     size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ 
  #ifdef FRAME_GROWS_DOWNWARD
    frame_offset -= size;
  #endif
***************
*** 772,777 ****
--- 775,783 ----
       use the least significant bytes of those that are allocated.  */
    if (BYTES_BIG_ENDIAN && mode != BLKmode)
      bigend_correction = size - GET_MODE_SIZE (mode);
+ 
+   if (bounds_checking_enabled) /* RWMJ */
+     size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
  
  #ifdef FRAME_GROWS_DOWNWARD
    function->frame_offset -= size;
*** gcc-2.7.2-orig/gcc.1	Tue Dec  5 21:24:22 1995
--- gcc-2.7.2/gcc.1	Tue Dec  5 21:29:58 1995
***************
*** 208,213 ****
--- 208,214 ----
  .B Debugging Options
  \-a
  .RI \-d letters
+ \-fbounds\-checking
  \-fpretend\-float
  \-g
  .RI \-g level
***************
*** 2261,2266 ****
--- 2262,2276 ----
  output of the actual floating constants, but the actual instruction
  sequence will probably be the same as GNU CC would make when running on
  the target machine.
+ .TP
+ .B \-fbounds\-checking
+ Add fine-grain bounds checking to pointers, array references, etc.
+ This results in a binary which is \fInot\fR suitable for production
+ use, but is a tremendous aid in debugging.
+ For full details, see ``A Bounds Checking C Compiler'' by
+ Richard W. M. Jones, rwmj@doc.ic.ac.uk.
+ A copy is included in the bounds checking package, directory
+ \fCbounds/report\fR.
  .TP
  .B \-save\-temps
  Store the usual \*(lqtemporary\*(rq intermediate files permanently; place them
*** gcc-2.7.2-orig/gcc.c	Thu Nov 16 00:57:04 1995
--- gcc-2.7.2/gcc.c	Thu Nov 16 16:40:10 1995
***************
*** 597,602 ****
--- 597,603 ----
  static int n_compilers;
  
  /* The default list of file name suffixes and their compilation specs.  */
+ /* Bounds-checking flags added by RWMJ. */
  
  static struct compiler default_compilers[] =
  {
***************
*** 607,612 ****
--- 608,614 ----
  	%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
          -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
  	%{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+         %{fbounds-checking:-D__BOUNDS_CHECKING_ON}\
  	%{!undef:%{!ansi:%p} %P} %{trigraphs} \
          %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
          %{traditional-cpp:-traditional}\
***************
*** 725,730 ****
--- 727,733 ----
  			%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
  			%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
  			%{static:} %{L*} %{T*} %o\
+                         %{fbounds-checking:libcheck.a%s} \
  			%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
  			%{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
  #else
***************
*** 735,740 ****
--- 738,744 ----
  			%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
  			%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
  			%{static:} %{L*} %D %{T*} %o\
+                         %{fbounds-checking:libcheck.a%s} \
  			%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
  			%{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
  #endif
*** gcc-2.7.2-orig/ginclude/stdarg.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/stdarg.h	Tue Jan 16 23:18:30 1996
***************
*** 80,91 ****
  
  #if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
  /* This is for little-endian machines; small args are padded upward.  */
! #define va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
  #else /* big-endian */
  /* This is for big-endian machines; small args are padded downward.  */
! #define va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP)					\
  		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
--- 80,91 ----
  
  #if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
  /* This is for little-endian machines; small args are padded upward.  */
! #define __std_va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
  #else /* big-endian */
  /* This is for big-endian machines; small args are padded downward.  */
! #define __std_va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP)					\
  		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
***************
*** 103,108 ****
--- 103,129 ----
  #endif /* not i860 */
  #endif /* not m88k */
  #endif /* not clipper */
+ 
+ /* Define va_arg in terms of __std_va_arg as appropriate for bounds
+  * checking.
+  * - RWMJ (16/1/96).
+  */
+ #ifndef __BOUNDS_CHECKING_ON
+ 
+ #define va_arg(AP,TYPE) __std_va_arg(AP,TYPE)
+ 
+ #else /* __BOUNDS_CHECKING_ON */
+ 
+ #define va_arg(AP,TYPE) \
+   ({extern int __bounds_debug_no_checking; \
+   int __t = __bounds_debug_no_checking; \
+   TYPE __r; \
+   __bounds_debug_no_checking = 1; \
+   __r = __std_va_arg(AP,TYPE); \
+   __bounds_debug_no_checking = __t; \
+   __r;})
+ 
+ #endif /* __BOUNDS_CHECKING_ON */
  
  #ifdef _STDARG_H
  /* Define va_list, if desired, from __gnuc_va_list. */
*** gcc-2.7.2-orig/ginclude/va-alpha.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/va-alpha.h	Tue Jan 16 23:19:53 1996
***************
*** 89,95 ****
    (((sizeof (__type) + __extension__ sizeof (long long) - 1)   \
      / __extension__ sizeof (long long)) * __extension__ sizeof (long long))
  
! #define va_arg(__va, __type)						\
  (*(((__va).__offset += __va_tsize (__type)),				\
     (__type *)(void *)((__va).__base + (__va).__offset			\
  	      - (((__builtin_classify_type (* (__type *) 0)		\
--- 89,95 ----
    (((sizeof (__type) + __extension__ sizeof (long long) - 1)   \
      / __extension__ sizeof (long long)) * __extension__ sizeof (long long))
  
! #define __std_va_arg(__va, __type)						\
  (*(((__va).__offset += __va_tsize (__type)),				\
     (__type *)(void *)((__va).__base + (__va).__offset			\
  	      - (((__builtin_classify_type (* (__type *) 0)		\
*** gcc-2.7.2-orig/ginclude/va-clipper.h	Fri Apr 14 19:42:57 1995
--- gcc-2.7.2/ginclude/va-clipper.h	Tue Jan 16 23:20:03 1996
***************
*** 45,51 ****
     ~(__alignof__ (TYPE) - 1),					\
    ((AP).__va_ap = ((AP).__va_ap + sizeof (int) - 1) & ~(sizeof (int) - 1)))
  
! #define va_arg(AP, TYPE) \
    (*((AP).__va_num < 2 && __builtin_classify_type (* (TYPE *)0) < 12	\
     ? (__builtin_classify_type (* (TYPE *)0) == 8			\
        ? ((TYPE *)(AP).__va_reg[2 * (AP).__va_num++ + 1])		\
--- 45,51 ----
     ~(__alignof__ (TYPE) - 1),					\
    ((AP).__va_ap = ((AP).__va_ap + sizeof (int) - 1) & ~(sizeof (int) - 1)))
  
! #define __std_va_arg(AP, TYPE) \
    (*((AP).__va_num < 2 && __builtin_classify_type (* (TYPE *)0) < 12	\
     ? (__builtin_classify_type (* (TYPE *)0) == 8			\
        ? ((TYPE *)(AP).__va_reg[2 * (AP).__va_num++ + 1])		\
*** gcc-2.7.2-orig/ginclude/va-h8300.h	Fri Feb 24 21:28:22 1995
--- gcc-2.7.2/ginclude/va-h8300.h	Tue Jan 16 23:20:12 1996
***************
*** 42,48 ****
  
  #endif /* _VARARGS_H */
  
! #define va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4		\
  					 ? sizeof (TYPE)		\
--- 42,48 ----
  
  #endif /* _VARARGS_H */
  
! #define __std_va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4		\
  					 ? sizeof (TYPE)		\
*** gcc-2.7.2-orig/ginclude/va-i860.h	Fri Feb 24 21:28:25 1995
--- gcc-2.7.2/ginclude/va-i860.h	Tue Jan 16 23:20:21 1996
***************
*** 121,127 ****
  #define __extension__
  #endif
  
! #define va_arg(__va, __type)						\
  __extension__								\
  (* (__type *)								\
  ({									\
--- 121,127 ----
  #define __extension__
  #endif
  
! #define __std_va_arg(__va, __type)						\
  __extension__								\
  (* (__type *)								\
  ({									\
*** gcc-2.7.2-orig/ginclude/va-i960.h	Wed Mar 22 21:40:27 1995
--- gcc-2.7.2/ginclude/va-i960.h	Tue Jan 16 23:20:29 1996
***************
*** 56,62 ****
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define	va_arg(AP, T)							\
  (									\
    (									\
      ((AP)[1] <= 48 && (__vpad ((AP)[1], T) > 48 || __vsiz (T) > 16))	\
--- 56,62 ----
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define	__std_va_arg(AP, T)							\
  (									\
    (									\
      ((AP)[1] <= 48 && (__vpad ((AP)[1], T) > 48 || __vsiz (T) > 16))	\
*** gcc-2.7.2-orig/ginclude/va-m88k.h	Fri Feb 24 21:28:31 1995
--- gcc-2.7.2/ginclude/va-m88k.h	Tue Jan 16 23:20:41 1996
***************
*** 70,76 ****
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define va_arg(AP,TYPE)							   \
    ( (AP).__va_arg = (((AP).__va_arg + (1 << (__alignof__(TYPE) >> 3)) - 1) \
  		     & ~((1 << (__alignof__(TYPE) >> 3)) - 1))		   \
      + __va_size(TYPE),							   \
--- 70,76 ----
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define __std_va_arg(AP,TYPE)							   \
    ( (AP).__va_arg = (((AP).__va_arg + (1 << (__alignof__(TYPE) >> 3)) - 1) \
  		     & ~((1 << (__alignof__(TYPE) >> 3)) - 1))		   \
      + __va_size(TYPE),							   \
*** gcc-2.7.2-orig/ginclude/va-mips.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/va-mips.h	Tue Jan 16 23:21:00 1996
***************
*** 77,87 ****
     right aligned).  */
  #ifdef __mips64
  #ifdef __MIPSEB__
! #define va_arg(__AP, __type)                                    \
    ((__type *) (void *) (__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \
  					 + __va_rounded_size (__type))))[-1]
  #else
! #define va_arg(__AP, __type)                                    \
    ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8)	\
  		     + __va_rounded_size (__type))),		\
     *(__type *) (void *) (__AP - __va_rounded_size (__type)))
--- 77,87 ----
     right aligned).  */
  #ifdef __mips64
  #ifdef __MIPSEB__
! #define __std_va_arg(__AP, __type)                                    \
    ((__type *) (void *) (__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8) \
  					 + __va_rounded_size (__type))))[-1]
  #else
! #define __std_va_arg(__AP, __type)                                    \
    ((__AP = (char *) ((((__PTRDIFF_TYPE__)__AP + 8 - 1) & -8)	\
  		     + __va_rounded_size (__type))),		\
     *(__type *) (void *) (__AP - __va_rounded_size (__type)))
***************
*** 91,97 ****
  
  #ifdef __MIPSEB__
  /* For big-endian machines.  */
! #define va_arg(__AP, __type)					\
    ((__AP = (char *) ((__alignof__ (__type) > 4			\
  		      ? ((int)__AP + 8 - 1) & -8		\
  		      : ((int)__AP + 4 - 1) & -4)		\
--- 91,97 ----
  
  #ifdef __MIPSEB__
  /* For big-endian machines.  */
! #define __std_va_arg(__AP, __type)					\
    ((__AP = (char *) ((__alignof__ (__type) > 4			\
  		      ? ((int)__AP + 8 - 1) & -8		\
  		      : ((int)__AP + 4 - 1) & -4)		\
***************
*** 99,105 ****
     *(__type *) (void *) (__AP - __va_rounded_size (__type)))
  #else
  /* For little-endian machines.  */
! #define va_arg(__AP, __type)						    \
    ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4	    \
  					  ? ((int)__AP + 8 - 1) & -8	    \
  					  : ((int)__AP + 4 - 1) & -4)	    \
--- 99,105 ----
     *(__type *) (void *) (__AP - __va_rounded_size (__type)))
  #else
  /* For little-endian machines.  */
! #define __std_va_arg(__AP, __type)						    \
    ((__type *) (void *) (__AP = (char *) ((__alignof__(__type) > 4	    \
  					  ? ((int)__AP + 8 - 1) & -8	    \
  					  : ((int)__AP + 4 - 1) & -4)	    \
*** gcc-2.7.2-orig/ginclude/va-pa.h	Fri Apr 14 19:43:01 1995
--- gcc-2.7.2/ginclude/va-pa.h	Tue Jan 16 23:21:09 1996
***************
*** 32,38 ****
  #define va_start(AP) __gnuc_va_start (AP)
  #endif
  
! #define va_arg(AP,TYPE)						\
    (*(sizeof(TYPE) > 8 ?						\
     ((AP = (__gnuc_va_list) ((char *)AP - sizeof (int))),	\
      (((TYPE *) (void *) (*((int *) (AP))))))			\
--- 32,38 ----
  #define va_start(AP) __gnuc_va_start (AP)
  #endif
  
! #define __std_va_arg(AP,TYPE)						\
    (*(sizeof(TYPE) > 8 ?						\
     ((AP = (__gnuc_va_list) ((char *)AP - sizeof (int))),	\
      (((TYPE *) (void *) (*((int *) (AP))))))			\
*** gcc-2.7.2-orig/ginclude/va-ppc.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/va-ppc.h	Tue Jan 16 23:21:16 1996
***************
*** 94,100 ****
  #define __va_aggregate_p(TYPE)	(__builtin_classify_type(*(TYPE *)0) >= 12)
  #define __va_size(TYPE)		((sizeof(TYPE) + sizeof (long) - 1) / sizeof (long))
  
! #define va_arg(AP,TYPE)							\
  __extension__ (*({							\
    register TYPE *__ptr;							\
  									\
--- 94,100 ----
  #define __va_aggregate_p(TYPE)	(__builtin_classify_type(*(TYPE *)0) >= 12)
  #define __va_size(TYPE)		((sizeof(TYPE) + sizeof (long) - 1) / sizeof (long))
  
! #define __std_va_arg(AP,TYPE)							\
  __extension__ (*({							\
    register TYPE *__ptr;							\
  									\
*** gcc-2.7.2-orig/ginclude/va-pyr.h	Fri Apr 14 19:43:07 1995
--- gcc-2.7.2/ginclude/va-pyr.h	Tue Jan 16 23:21:25 1996
***************
*** 109,115 ****
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define va_arg(_AP, _MODE)	\
  __extension__								\
  (*({__voidptr *__ap = (__voidptr*)&_AP;					\
    register int __size = sizeof (_MODE);					\
--- 109,115 ----
  
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.  */
! #define __std_va_arg(_AP, _MODE)	\
  __extension__								\
  (*({__voidptr *__ap = (__voidptr*)&_AP;					\
    register int __size = sizeof (_MODE);					\
*** gcc-2.7.2-orig/ginclude/va-sparc.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/va-sparc.h	Tue Jan 16 23:21:38 1996
***************
*** 131,137 ****
  
  #ifdef __sparc_v9__
  
! #define va_arg(pvar,TYPE)					\
  __extension__							\
  (*({int __type = __builtin_classify_type (* (TYPE *) 0);	\
    void * __result;						\
--- 131,137 ----
  
  #ifdef __sparc_v9__
  
! #define __std_va_arg(pvar,TYPE)					\
  __extension__							\
  (*({int __type = __builtin_classify_type (* (TYPE *) 0);	\
    void * __result;						\
***************
*** 183,189 ****
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.
     The casts to char * avoid warnings about invalid pointer arithmetic.  */
! #define va_arg(pvar,TYPE)					\
  __extension__							\
  (*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
        || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \
--- 183,189 ----
  /* We cast to void * and then to TYPE * because this avoids
     a warning about increasing the alignment requirement.
     The casts to char * avoid warnings about invalid pointer arithmetic.  */
! #define __std_va_arg(pvar,TYPE)					\
  __extension__							\
  (*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
        || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \
*** gcc-2.7.2-orig/ginclude/va-spur.h	Fri Apr 14 19:43:14 1995
--- gcc-2.7.2/ginclude/va-spur.h	Tue Jan 16 23:21:47 1996
***************
*** 36,42 ****
  #define __extension__
  #endif
  
! #define va_arg(pvar,type)  \
  __extension__ \
      (*({  type *__va_result; \
          if ((pvar).__pnt >= 20) { \
--- 36,42 ----
  #define __extension__
  #endif
  
! #define __va_arg(pvar,type)  \
  __extension__ \
      (*({  type *__va_result; \
          if ((pvar).__pnt >= 20) { \
*** gcc-2.7.2-orig/ginclude/varargs.h	Thu Nov 16 00:57:11 1995
--- gcc-2.7.2/ginclude/varargs.h	Tue Jan 16 23:19:42 1996
***************
*** 99,110 ****
  
  #if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
  /* This is for little-endian machines; small args are padded upward.  */
! #define va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
  #else /* big-endian */
  /* This is for big-endian machines; small args are padded downward.  */
! #define va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP)					\
  		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
--- 99,110 ----
  
  #if defined (__arm__) || defined (__i386__) || defined (__i860__) || defined (__ns32000__) || defined (__vax__)
  /* This is for little-endian machines; small args are padded upward.  */
! #define __std_va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
  #else /* big-endian */
  /* This is for big-endian machines; small args are padded downward.  */
! #define __std_va_arg(AP, TYPE)						\
   (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)),	\
    *((TYPE *) (void *) ((char *) (AP)					\
  		       - ((sizeof (TYPE) < __va_rounded_size (char)	\
***************
*** 123,128 ****
--- 123,150 ----
  #endif /* not mips */
  #endif /* not spur */
  #endif /* not sparc */
+ 
+ /* Define va_arg in terms of __std_va_arg as appropriate for bounds
+  * checking.
+  * - RWMJ (16/1/96).
+  */
+ #ifndef __BOUNDS_CHECKING_ON
+ 
+ #define va_arg(AP,TYPE) __std_va_arg(AP,TYPE)
+ 
+ #else /* __BOUNDS_CHECKING_ON */
+ 
+ #define va_arg(AP,TYPE) \
+   ({extern int __bounds_debug_no_checking; \
+   int __t = __bounds_debug_no_checking; \
+   TYPE __r; \
+   __bounds_debug_no_checking = 1; \
+   __r = __std_va_arg(AP,TYPE); \
+   __bounds_debug_no_checking = __t; \
+   __r;})
+ 
+ #endif /* __BOUNDS_CHECKING_ON */
+ 
  #endif /* not _VARARGS_H */
  
  /* Define va_list from __gnuc_va_list.  */
*** gcc-2.7.2-orig/invoke.texi	Thu Nov 16 00:57:18 1995
--- gcc-2.7.2/invoke.texi	Thu Nov 16 16:40:21 1995
***************
*** 134,139 ****
--- 134,140 ----
  -ggdb  -gstabs  -gstabs+  -gxcoff  -gxcoff+
  -p  -pg  -print-file-name=@var{library}  -print-libgcc-file-name
  -print-prog-name=@var{program}  -print-search-dirs  -save-temps
+ -fbounds-checking
  @end smallexample
  
  @item Optimization Options
***************
*** 1581,1586 ****
--- 1582,1592 ----
  This data could be analyzed by a program like @code{tcov}.  Note,
  however, that the format of the data is not what @code{tcov} expects.
  Eventually GNU @code{gprof} should be extended to process this data.
+ 
+ @cindex @code{-fbounds-checking}
+ @item -fbounds-checking
+ Add extra code to check array bounds and pointers at run time. See
+ @xref{Bounds Checking}. This option only works with C.
  
  @item -d@var{letters}
  Says to make debugging dumps during compilation at times specified by
*** gcc-2.7.2-orig/libgcc2.c	Tue Dec  5 21:24:25 1995
--- gcc-2.7.2/libgcc2.c	Tue Dec  5 21:30:01 1995
***************
*** 2092,2097 ****
--- 2092,2103 ----
  #define SYMBOL__MAIN __main
  #endif
  
+ /* RWMJ:
+  * If there are any bounds-checked modules in this program at all, then
+  * __bounds_initialize_library will be called, which sets the following flag.
+  */
+ int __bounds_checking_on = 0;
+ 
  #if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
  /* Run all the global destructors on exit from the program.  */
  
*** gcc-2.7.2-orig/optabs.c	Thu Nov 16 00:57:39 1995
--- gcc-2.7.2/optabs.c	Thu Nov 16 16:40:38 1995
***************
*** 4206,4217 ****
    truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2");
    trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2");
  
!   memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
!   bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
!   memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
!   bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
!   memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
!   bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
  
    eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
    nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
--- 4206,4233 ----
    truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2");
    trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2");
  
!   /* In bounds checking mode, we need to call the unchecked versions of some
!    * of these functions. The '__bounds_...' functions are supplied by libcheck.
!    * (RWMJ, 25/4/95).
!    */
!   if (!bounds_checking_enabled)
!     {
!       memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
!       bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
!       memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
!       bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
!       memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
!       bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
!     }
!   else
!     {
!       memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memcpy");
!       bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
!       memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memcmp");
!       bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
!       memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__bounds_memset");
!       bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
!     }
  
    eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
    nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
*** gcc-2.7.2-orig/print-tree.c	Thu Jun 15 07:56:40 1995
--- gcc-2.7.2/print-tree.c	Tue Jul  4 11:11:09 1995
***************
*** 434,440 ****
  
        print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
        print_node (file, "result", DECL_RESULT (node), indent + 4);
!       print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4);
  
        print_lang_decl (file, node, indent);
  
--- 434,443 ----
  
        print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
        print_node (file, "result", DECL_RESULT (node), indent + 4);
! 
!       /* Want full printing of the initial node here. (RWMJ) */
! /*      print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); */
!       print_node (file, "initial", DECL_INITIAL (node), indent + 4);
  
        print_lang_decl (file, node, indent);
  
*** gcc-2.7.2-orig/stmt.c	Thu Nov 16 00:57:58 1995
--- gcc-2.7.2/stmt.c	Thu Nov 16 16:45:29 1995
***************
*** 1246,1252 ****
  	      f->before_jump
  		= emit_insns_after (cleanup_insns, f->before_jump);
  
! 	      f->cleanup_list_list = TREE_CHAIN (lists);
  	    }
  
  	if (stack_level)
--- 1246,1253 ----
  	      f->before_jump
  		= emit_insns_after (cleanup_insns, f->before_jump);
  
! 	      if (!bounds_checking_enabled)
! 	        f->cleanup_list_list = TREE_CHAIN (lists);
  	    }
  
  	if (stack_level)
***************
*** 3310,3316 ****
  }
  
  /* Generate RTL for the automatic variable declaration DECL.
!    (Other kinds of declarations are simply ignored if seen here.)  */
  
  void
  expand_decl (decl)
--- 3311,3324 ----
  }
  
  /* Generate RTL for the automatic variable declaration DECL.
!    (Other kinds of declarations are simply ignored if seen here.)
! 
!    In bounds checking mode (for C only at present) we insert an extra byte
!    after automatic variables. This lets us validly generate pointers to
!    the end of the object + 1. Notice that in bounds checking mode, no
!    real automatic variables make it into registers.
!    (RWMJ)
!    */
  
  void
  expand_decl (decl)
***************
*** 3351,3356 ****
--- 3359,3366 ----
        else
  	/* An initializer is going to decide the size of this array.
  	   Until we know the size, represent its address with a reg.  */
+ 	/* FIXME: RWMJ: Bounds checking needs to know about this. */
+ 	/* -- 19/6/95, I don't think it needs to. */
  	DECL_RTL (decl) = gen_rtx (MEM, BLKmode, gen_reg_rtx (Pmode));
        MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (type);
      }
***************
*** 3364,3369 ****
--- 3374,3381 ----
  	   && (DECL_REGISTER (decl) || ! obey_regdecls))
      {
        /* Automatic variable that can go in a register.  */
+       /* In bounds checking mode, no automatic variables make it into regs,
+        * since we take the address of all of them.	*/
        int unsignedp = TREE_UNSIGNED (type);
        enum machine_mode reg_mode
  	= promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
***************
*** 3395,3400 ****
--- 3407,3413 ----
        /* Variable of fixed size that goes on the stack.  */
        rtx oldaddr = 0;
        rtx addr;
+       int size;
  
        /* If we previously made RTL for this decl, it must be an array
  	 whose size was determined by the initializer.
***************
*** 3408,3419 ****
  	  oldaddr = XEXP (DECL_RTL (decl), 0);
  	}
  
        DECL_RTL (decl)
! 	= assign_stack_temp (DECL_MODE (decl),
! 			     ((TREE_INT_CST_LOW (DECL_SIZE (decl))
! 			       + BITS_PER_UNIT - 1)
! 			      / BITS_PER_UNIT),
! 			     1);
        MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
  
        /* Set alignment we actually gave this decl.  */
--- 3421,3436 ----
  	  oldaddr = XEXP (DECL_RTL (decl), 0);
  	}
  
+       size = ((TREE_INT_CST_LOW (DECL_SIZE (decl))
+ 	       + BITS_PER_UNIT - 1)
+ 	      / BITS_PER_UNIT);
+       /* Add a byte of padding between bounds checked variables. (RWMJ). */
+       if (bounds_checking_enabled)
+ 	size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ 
        DECL_RTL (decl)
! 	= assign_stack_temp (DECL_MODE (decl), size, 1);
! 
        MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (TREE_TYPE (decl));
  
        /* Set alignment we actually gave this decl.  */
***************
*** 3455,3464 ****
  	}
  
        /* Compute the variable's size, in bytes.  */
!       size = expand_expr (size_binop (CEIL_DIV_EXPR,
! 				      DECL_SIZE (decl),
! 				      size_int (BITS_PER_UNIT)),
! 			  NULL_RTX, VOIDmode, 0);
        free_temp_slots ();
  
        /* Allocate space on the stack for the variable.  */
--- 3472,3491 ----
  	}
  
        /* Compute the variable's size, in bytes.  */
!       /* In bounds checking mode, make the size one byte larger. (RWMJ) */
!       if (!bounds_checking_enabled)
! 	size = expand_expr (size_binop (CEIL_DIV_EXPR,
! 					DECL_SIZE (decl),
! 					size_int (BITS_PER_UNIT)),
! 			    NULL_RTX, VOIDmode, 0);
!       else
! 	size = expand_expr (size_binop (CEIL_DIV_EXPR,
! 					size_binop (PLUS_EXPR,
! 						    DECL_SIZE (decl),
! 						    size_int (BIGGEST_ALIGNMENT/
! 							      BITS_PER_UNIT)),
! 					size_int (BITS_PER_UNIT)),
! 			    NULL_RTX, VOIDmode, 0);
        free_temp_slots ();
  
        /* Allocate space on the stack for the variable.  */
*** gcc-2.7.2-orig/toplev.c	Thu Nov 16 00:58:07 1995
--- gcc-2.7.2/toplev.c	Thu Nov 16 16:41:02 1995
***************
*** 521,526 ****
--- 521,533 ----
  /* Tag all structures with __attribute__(packed) */
  int flag_pack_struct = 0;
  
+ /* Flag indicating that bounds checking has been enabled in the C
+  * front end. There are some changes in `varasm.c' that depend upon
+  * the state of this flag. (RWMJ)
+  */
+ 
+ int bounds_checking_enabled = 0;
+ 
  /* Table of language-independent -f options.
     STRING is the option name.  VARIABLE is the address of the variable.
     ON_VALUE is the value to store in VARIABLE
***************
*** 647,652 ****
--- 654,662 ----
    "-Wno-trigraphs",
    "-Wwrite-strings",
    "-Wno-write-strings",
+ 
+   /* This is for bounds checking code. (RWMJ). */
+   "-fbounds-checking",			/* Switches default options on. */
  
    /* these are for obj c */
    "-lang-objc",
*** gcc-2.7.2-orig/varasm.c	Thu Nov 16 00:58:12 1995
--- gcc-2.7.2/varasm.c	Thu Nov 16 16:41:08 1995
***************
*** 121,126 ****
--- 121,127 ----
  struct rtx_const;
  struct pool_constant;
  
+ static char *my_strsave                 PROTO((char *));
  static void bc_make_decl_rtl		PROTO((tree, char *, int));
  static char *strip_reg_name		PROTO((char *));
  static void bc_output_ascii		PROTO((FILE *, char *, int));
***************
*** 145,151 ****
--- 146,166 ----
  static int output_addressed_constants	PROTO((tree));
  static void bc_assemble_integer		PROTO((tree, int));
  static void output_constructor		PROTO((tree, int));
+ 
+ /* In bounds checking mode, we build a list of private statics allocated
+  * in the output file. At the end, we build the list into an array, so we
+  * can find all these strings and things.
+  */
+ static struct private_statics_elem {
+   struct private_statics_elem *next;
+   char *name;				/* Name for this object. */
+   int name_label;			/* (Private: label for this name). */
+   char *label;				/* Assembler label. */
+   int size;				/* Size of the declaration. */
+ } *private_statics_list = NULL;
+ 
  
+ 
  #ifdef EXTRA_SECTIONS
  static enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section
    = no_section;
***************
*** 580,585 ****
--- 595,679 ----
  	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
  	      name = obstack_copy0 (saveable_obstack, label, strlen (label));
  	      var_labelno++;
+ 
+ 	      /* In bounds checked mode, we want to remember this assembler
+ 	       * label till the end of the file.		(RWMJ).
+ 	       */
+ 	      if (bounds_checking_enabled
+ 		  /* Don't check __FUNCTION__ and __PRETTY_FUNCTION__. */
+ 		  && !DECL_IN_SYSTEM_HEADER (decl))
+ 		{
+ 		  struct private_statics_elem *private_static;
+ 		  int size;
+ 		  tree size_tree;
+ 
+ 		  /* Work out the size. If it's not constant, then we will
+ 		   * be in trouble.
+ 		   */
+ 		  if (TREE_CODE (decl) != VAR_DECL
+ 		      || !DECL_INITIAL (decl)
+ 		      || TREE_CODE (DECL_INITIAL (decl)) != STRING_CST)
+ 		    {
+ 		      if (DECL_SIZE (decl) == 0)
+ 			layout_decl (decl, 0);
+ 		      if (DECL_SIZE (decl) != 0)
+ 			size_tree = size_binop (CEIL_DIV_EXPR,
+ 						DECL_SIZE (decl),
+ 						size_int (BITS_PER_UNIT));
+ 		      if (DECL_SIZE (decl) == 0 ||
+ 			  TREE_CODE (size_tree) != INTEGER_CST)
+ 			{
+ 			  warning ("size of static variable in function must be fixed for bounds checking");
+ 			  goto no_check;
+ 			}
+ 		    }
+ 		  else
+ 		    {
+ 		      /* This is for string declarations like `static char
+ 		       * p [] = "...";' where we can get the size (reliably?)
+ 		       * from the type.
+ 		       */
+ 		      size_tree = TYPE_SIZE (TREE_TYPE (DECL_INITIAL (decl)));
+ 		      if (size_tree)
+ 			size_tree = size_binop (CEIL_DIV_EXPR,
+ 						size_tree,
+ 						size_int (BITS_PER_UNIT));
+ 		      if (!size_tree ||
+ 			  TREE_CODE (size_tree) != INTEGER_CST)
+ 			{
+ 			  warning ("size of static string variable in function must be fixed for bounds checking");
+ 			  goto no_check;
+ 			}
+ 		    }
+ 		  size = TREE_INT_CST_LOW (size_tree);
+ 		  if (TREE_INT_CST_HIGH (size_tree) != 0)
+ 		    {
+ 		      warning ("static variable in function is too large to bounds check");
+ 		      goto no_check;
+ 		    }
+ 		  if (size == 0)
+ 		    {
+ 		      /* Couldn't determine the size. Declarations like
+ 		       * 'static int i[] = {0,1,2};' are like this. To do
+ 		       * this, look at 'output_constructor():total_bytes'
+ 		       * which walks over such a constructor, finding its
+ 		       * size.
+ 		       */
+ 		      warning ("static variable with no size cannot be bounds checked");
+ 		      goto no_check;
+ 		    }
+ 		  private_static
+ 		    = (struct private_statics_elem *)
+ 		    xmalloc (sizeof (struct private_statics_elem));
+ 		  private_static->name = my_strsave (name);
+ 		  private_static->label = my_strsave (label);
+ 		  private_static->size = size;
+ 		  private_static->next = private_statics_list;
+ 		  private_statics_list = private_static;
+ 
+ 		  no_check:
+ 		  ;
+ 		}
  	    }
  
  	  if (name == 0)
***************
*** 1102,1107 ****
--- 1196,1207 ----
        /* Don't allocate zero bytes of common,
  	 since that means "undefined external" in the linker.  */
        if (size == 0) rounded = 1;
+       /* In bounds checking mode, pad with 1 byte afterwards. (RWMJ) */
+       if (bounds_checking_enabled) {
+ 	/* We will fix this in a moment ... */
+ 	size += BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ 	rounded += BIGGEST_ALIGNMENT;
+       }
        /* Round size up to multiple of BIGGEST_ALIGNMENT bits
  	 so that each uninitialized object starts on such a boundary.  */
        rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
***************
*** 1175,1180 ****
--- 1275,1285 ----
  #endif
  	      }
  	}
+ 
+       /* In bounds checking mode, we `fixed' size by adding 1 for padding,
+        * earlier so subtract 1 again. (RWMJ) */
+       if (bounds_checking_enabled) size -= BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ 
        goto finish;
      }
  
***************
*** 1338,1344 ****
    /* Do any machine/system dependent processing of the object.  */
  #ifdef ASM_DECLARE_OBJECT_NAME
    last_assemble_variable_decl = decl;
!   ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
  #else
    /* Standard thing is just output label for the object.  */
    if (output_bytecode)
--- 1443,1465 ----
    /* Do any machine/system dependent processing of the object.  */
  #ifdef ASM_DECLARE_OBJECT_NAME
    last_assemble_variable_decl = decl;
! 
!   /* Patched by HtB to solve `verbose' bug. See bounds/BUGS.	(RWMJ).
!    */
!   if (bounds_checking_enabled
!       && TREE_TYPE(decl) != error_mark_node
!       && TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
!     {
!       tree save_size = TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
!       TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE(decl))) =
! 	size_binop (PLUS_EXPR,
! 		    TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))),
! 		    size_int(BIGGEST_ALIGNMENT));
!       ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
!       TYPE_SIZE (TYPE_MAIN_VARIANT (TREE_TYPE (decl))) = save_size;
!     }
!   else
!     ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
  #else
    /* Standard thing is just output label for the object.  */
    if (output_bytecode)
***************
*** 1355,1360 ****
--- 1476,1487 ----
        else
  	/* Leave space for it.  */
  	assemble_zeros (TREE_INT_CST_LOW (size_tree));
+ 
+       /* In bounds checking mode, add a single byte of padding after the
+        * variable.
+        */
+       if (bounds_checking_enabled)
+ 	assemble_zeros (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
      }
  
   finish:
***************
*** 1433,1438 ****
--- 1560,1679 ----
      }
  }
  
+ /* In bounds checking mode, build a table at the end of the file containing
+  * pointers and sizes of all private static data in the file.
+  * (RWMJ)
+  */
+ 
+ void
+ assemble_private_statics_table ()
+ {
+   struct private_statics_elem *p, *p_next;
+   rtx ptr_rtx, size_rtx, name_rtx;
+   int align, this_label_no = 0;
+   char label[256];
+ 
+   /* This table used to go in readonly_data_section, but unfortunately
+    * this broke AIX on RS/6000 machines. The error message was `data adcons
+    * in readonly sections' where (I presume) an `adcon' is an addressable
+    * constant. Anyway, I've put this in the ordinary data section for
+    * now. A correct solution probably involves looking at the `SELECT_
+    * SECTION' macro.
+    */
+ /*  readonly_data_section (); */
+   data_section ();
+ 
+   /* Align it to the default alignment for integers. Take care not to align
+    * bigger than the maximum the object file format will allow. Increase
+    * alignment on machines that can benefit.
+    */
+   align = BIGGEST_ALIGNMENT;
+ #ifdef DATA_ALIGNMENT
+   align = DATA_ALIGNMENT (integer_type_node, align);
+ #endif
+   if (align > BITS_PER_UNIT)
+     ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+ 
+   /* Write out the label for this object.
+    */
+   ASM_OUTPUT_LABEL (asm_out_file, "__bounds_private_statics");
+ 
+   /* Write out the elements in the array, ie. a list of (label_pointer,
+    * size, name_pointer).
+    */
+   for (p = private_statics_list; p; p = p->next) {
+     /* Write a pointer to the object.
+      */
+     ptr_rtx = gen_rtx (SYMBOL_REF, Pmode, p->label);
+ #if POINTER_SIZE == 64
+     ASM_OUTPUT_DOUBLE_INT (asm_out_file, ptr_rtx);
+ #else
+     ASM_OUTPUT_INT (asm_out_file, ptr_rtx);
+ #endif
+ 
+     /* Write the size of the object.
+      */
+     size_rtx = GEN_INT (p->size);
+     ASM_OUTPUT_INT (asm_out_file, size_rtx);
+ #if POINTER_SIZE == 64
+     ASM_OUTPUT_INT (asm_out_file, const0_rtx);
+ #endif
+ 
+     /* Write out a pointer to the object's name. We write the names out
+      * afterwards.
+      */
+     if (p->name != NULL)
+       {
+ 	p->name_label = this_label_no ++;
+ 	ASM_GENERATE_INTERNAL_LABEL (label, "LPS", p->name_label);
+ 	name_rtx = gen_rtx (SYMBOL_REF, Pmode, label);
+ #if POINTER_SIZE == 64
+ 	ASM_OUTPUT_DOUBLE_INT (asm_out_file, name_rtx);
+ #else
+ 	ASM_OUTPUT_INT (asm_out_file, name_rtx);
+ #endif
+       }
+     else
+       {
+ #if POINTER_SIZE == 64
+ 	ASM_OUTPUT_DOUBLE_INT (asm_out_file, const0_rtx);
+ #else
+ 	ASM_OUTPUT_INT (asm_out_file, const0_rtx);
+ #endif
+       }	
+   }
+ 
+   /* NULL-terminate the array.
+    */
+ #if POINTER_SIZE == 64
+   ASM_OUTPUT_DOUBLE_INT (asm_out_file, const0_rtx);
+   ASM_OUTPUT_DOUBLE_INT (asm_out_file, const0_rtx);
+   ASM_OUTPUT_DOUBLE_INT (asm_out_file, const0_rtx);
+ #else
+   ASM_OUTPUT_INT (asm_out_file, const0_rtx);
+   ASM_OUTPUT_INT (asm_out_file, const0_rtx);
+   ASM_OUTPUT_INT (asm_out_file, const0_rtx);
+ #endif
+ 
+   /* Write out the object names that we referred to in the above table.
+    */
+   for (p = private_statics_list; p; p = p->next)
+     if (p->name != NULL)
+       {
+ 	ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPS", p->name_label);
+ 	assemble_string (p->name, strlen (p->name) + 1);
+       }
+ 
+   /* For completeness, free up this list.
+    */
+   for (p = private_statics_list; p; p = p_next)
+     {
+       p_next = p->next;
+       free (p);
+     }
+   private_statics_list = NULL;
+ }
+ 
  /* Output text storage for constructor CONSTR. */
  
  void
***************
*** 2792,2798 ****
       int reloc;
       int labelno;
  {
!   int align;
  
    if (IN_NAMED_SECTION (exp))
      named_section (exp, NULL);
--- 3033,3039 ----
       int reloc;
       int labelno;
  {
!   int align, size;
  
    if (IN_NAMED_SECTION (exp))
      named_section (exp, NULL);
***************
*** 2832,2842 ****
    ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
  
    /* Output the value of EXP.  */
!   output_constant (exp,
! 		   (TREE_CODE (exp) == STRING_CST
! 		    ? TREE_STRING_LENGTH (exp)
! 		    : int_size_in_bytes (TREE_TYPE (exp))));
  
  }
  
  /* Similar hash facility for making memory-constants
--- 3073,3145 ----
    ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
  
    /* Output the value of EXP.  */
!   size = TREE_CODE (exp) == STRING_CST		/* Calculate size in bytes. */
!     ? TREE_STRING_LENGTH (exp)
!     : int_size_in_bytes (TREE_TYPE (exp));
!   output_constant (exp, size);
! 
!   /* In bounds checked mode, put a byte of padding after addressed
!    * constants. Then add the assembler label and the (real) byte size to
!    * a list. We will output this list as a private array at the end, so
!    * we can pick up these static constants for checking.	(RWMJ).
!    */
!   if (bounds_checking_enabled)
!     {
!       struct private_statics_elem *private_static;
!       char label [256];
! 
!       assemble_zeros (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
!       if (size != 0)
! 	{
! 	  private_static
! 	    = (struct private_statics_elem *)
! 	    xmalloc (sizeof (struct private_statics_elem));
! 	  ASM_GENERATE_INTERNAL_LABEL (label, "LC", labelno);
! 	  private_static->name = NULL;		/* Object has no name. */
! 	  private_static->label = my_strsave (label);
! 	  private_static->size = size;
! 	  private_static->next = private_statics_list;
! 	  private_statics_list = private_static;
! 	}
!       else
! 	warning ("cannot generate bounds checking code for zero sized static object");
!     }
! }
! 
! /* Add external data definitions to the private_static list. Use a
!  * negative size to flag this is an external data definition.
!  */
! void
! bounds_external_declaration ( decl, len )
!     tree decl;
!     int len;
! {
! #if 1
!   int i;
  
+   for (i = 0 ; i < len ; i++, decl = TREE_CHAIN (decl)) {
+ 
+     if (TREE_CODE(decl) == VAR_DECL
+         && DECL_EXTERNAL (decl)
+         && TREE_USED(decl))
+       {
+         int size = int_size_in_bytes (TREE_TYPE (decl));
+ 
+         if (size > 0) {
+           struct private_statics_elem *private_static;
+           char *label = my_strsave(IDENTIFIER_POINTER (DECL_NAME (decl))) ;
+ 
+           private_static = (struct private_statics_elem *)
+ 			    xmalloc (sizeof (struct private_statics_elem));
+           private_static->name = label;
+           private_static->label = label;
+           private_static->size = -size;
+           private_static->next = private_statics_list;
+           private_statics_list = private_static;
+         }
+       }
+   }
+ #endif
  }
  
  /* Similar hash facility for making memory-constants
***************
*** 4061,4064 ****
--- 4364,4380 ----
  #else
    warning ("alias definitions not supported in this configuration");
  #endif
+ }
+ 
+ /* `my_strsave' is a helper function that just duplicates a string, and
+  * returns a pointer to the duplicated string.			(RWMJ).
+  * Note: This string ought probably to be allocated on the permanent
+  * obstack.
+  * Note (2): This is a memory leak, but only a very minor one.
+  */
+ static char *
+ my_strsave (str)
+   char *str;
+ {
+   return strcpy ((char *) xmalloc (strlen (str) + 1), str);
  }
*** gcc-2.7.2-orig/Makefile.in	Tue Dec  5 21:23:57 1995
--- gcc-2.7.2/Makefile.in	Wed Jan 10 13:37:08 1996
***************
*** 229,234 ****
--- 229,239 ----
  # and the rule for installing it.
  INSTALL_LIBGCC = install-libgcc
  
+ # Specify a rule for making the bounds checking library, (RWMJ)
+ LIBCHECK = libcheck.a
+ # and the rule for installing it.
+ INSTALL_LIBCHECK = install-libcheck
+ 
  # Specify the rule for actually making libgcc1.a.
  # The value may be empty; that means to do absolutely nothing
  # with or for libgcc1.a.
***************
*** 332,338 ****
  
  # List of things which should already be built whenever we try to use xgcc
  # to link anything.
! GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(EXTRA_PROGRAMS) $(USE_COLLECT2) $(EXTRA_PARTS)
  
  # Directory to link to, when using the target `maketest'.
  DIR = ../gcc
--- 337,343 ----
  
  # List of things which should already be built whenever we try to use xgcc
  # to link anything.
! GCC_PARTS=$(GCC_PASSES) $(LIBGCC) $(LIBCHECK) $(EXTRA_PROGRAMS) $(USE_COLLECT2) $(EXTRA_PARTS)
  
  # Directory to link to, when using the target `maketest'.
  DIR = ../gcc
***************
*** 499,509 ****
  
  # Language-specific object files for C.
  C_OBJS = c-parse.o c-lang.o c-lex.o c-pragma.o \
!    c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o
  
  # Language-specific object files for Objective C.
  OBJC_OBJS = objc-parse.o objc-act.o c-lex.o c-pragma.o \
!    c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o
  
  # Files specific to the C interpreter bytecode compiler(s).
  BC_OBJS = bc-emit.o bc-optab.o
--- 504,516 ----
  
  # Language-specific object files for C.
  C_OBJS = c-parse.o c-lang.o c-lex.o c-pragma.o \
!    c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o \
!    c-bounds.o
  
  # Language-specific object files for Objective C.
  OBJC_OBJS = objc-parse.o objc-act.o c-lex.o c-pragma.o \
!    c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o \
!    c-bounds.o
  
  # Files specific to the C interpreter bytecode compiler(s).
  BC_OBJS = bc-emit.o bc-optab.o
***************
*** 928,933 ****
--- 935,968 ----
  # so that libgcc.a itself remains nonexistent if compilation is aborted.
  	mv tmplibgcc.a libgcc.a
  
+ # Build the bounds checking library for GCC.
+ $(LIBCHECK): force
+ 	if [ -d bounds ]; then true; else mkdir bounds; fi; \
+ 	if [ -d bounds/lib ]; then true; else mkdir bounds/lib; fi; \
+ 	thisdir1=`pwd`; \
+ 	srcdir1=`cd $(srcdir); pwd`; \
+ 	cd bounds/lib; \
+ 	$(MAKE) -f $${srcdir1}/bounds/lib/Makefile libcheck.a \
+ 	  srcdir=$${srcdir1} tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+ 	  GCC_FOR_TARGET="$${thisdir1}/xgcc -B$${thisdir1}/" \
+ 	  GCC_CFLAGS="$(GCC_CFLAGS)"
+ 	-rm -f $(LIBCHECK)
+ 	ln bounds/lib/libcheck.a . >/dev/null 2>&1 || cp bounds/lib/libcheck.a .
+ 	-if $(RANLIB_TEST) ; then $(RANLIB) $(LIBCHECK); else true; fi
+ 
+ # This is used by bounds/lib/Makefile if the user runs that directly.
+ sublibcheck.a: force
+ 	thisdir1=`pwd`; \
+ 	srcdir1=`cd $(srcdir); pwd`; \
+ 	cd bounds/lib; \
+ 	$(MAKE) -f $$srcdir1/bounds/lib/Makefile libcheck.a \
+ 	  srcdir=$$srcdir1 tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+ 	  GCC_FOR_TARGET="$$thisdir1/xgcc -B$$thisdir1/" \
+ 	  GCC_CFLAGS="$(GCC_CFLAGS)"
+ 	-rm -f $(LIBCHECK)
+ 	ln bounds/lib/libcheck.a . >/dev/null 2>&1 || cp bounds/lib/libcheck.a .
+ 	-if $(RANLIB_TEST) ; then $(RANLIB) $(LIBCHECK); else true; fi
+ 
  # Use the genmultilib shell script to generate the information the gcc
  # driver program needs to select the library directory based on the
  # switches.
***************
*** 1955,1960 ****
--- 1990,2003 ----
  # but what better way is there?
  	-rm -f libgcc.a libgcc1.a libgcc1-asm.a libgcc2.a libgcc2.ready
  	-rm -f libgcc1.null
+ # Clean up libcheck and bounds/ subdirectory. (RWMJ)
+ 	-rm -f $(LIBCHECK)
+ 	if [ -d bounds/lib ]; then \
+ 	  srcdir1=`cd $(srcdir); pwd`; \
+ 	  cd bounds/lib; \
+ 	  $(MAKE) -f $$srcdir1/bounds/lib/Makefile srcdir=$$srcdir1 mostlyclean; \
+ 	  else true; \
+ 	fi
  	-rm -f *.dvi
  	-rm -f */*.dvi
  	-if [ -f md.pre-cpp ]; then \
***************
*** 2022,2028 ****
  # Install the driver last so that the window when things are
  # broken is small.
  install-normal: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \
!     install-libobjc install-man install-info lang.install-normal install-driver
  
  # Do nothing while making gcc with a cross-compiler. The person who
  # makes gcc for the target machine has to know how to put a complete
--- 2065,2073 ----
  # Install the driver last so that the window when things are
  # broken is small.
  install-normal: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \
! 	$(INSTALL_LIBCHECK) \
! 	install-libobjc install-man install-info \
! 	lang.install-normal install-driver
  
  # Do nothing while making gcc with a cross-compiler. The person who
  # makes gcc for the target machine has to know how to put a complete
***************
*** 2156,2161 ****
--- 2201,2216 ----
  	  if $(RANLIB_TEST) ; then \
  	    (cd $(libsubdir); $(RANLIB) libgcc.a); else true; fi; \
  	  chmod a-x $(libsubdir)/libgcc.a; \
+ 	else true; fi
+ 
+ # Install the checking library.
+ install-libcheck: libcheck.a install-dir
+ 	-if [ -f $(LIBCHECK) ]; then \
+ 	  rm -f $(libsubdir)/libcheck.a; \
+ 	  $(INSTALL_DATA) $(LIBCHECK) $(libsubdir)/libcheck.a; \
+ 	  if $(RANLIB_TEST); then \
+ 	    (cd $(libsubdir); $(RANLIB) libcheck.a); else true; fi; \
+ 	  chmod a-x $(libsubdir)/libcheck.a; \
  	else true; fi
  
  # Install multiple versions of libgcc.a.
*** gcc-2.7.2-orig/cp/Makefile.in	Thu Nov 16 00:55:57 1995
--- gcc-2.7.2/cp/Makefile.in	Thu Nov 16 16:38:54 1995
***************
*** 160,166 ****
  
  CXX_OBJS = call.o decl.o errfn.o expr.o pt.o sig.o typeck2.o \
   class.o decl2.o error.o gc.o lex.o parse.o ptree.o spew.o typeck.o cvt.o \
!  edsel.o except.o init.o method.o search.o tree.o xref.o repo.o
  
  # Language-independent object files.
  OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
--- 160,167 ----
  
  CXX_OBJS = call.o decl.o errfn.o expr.o pt.o sig.o typeck2.o \
   class.o decl2.o error.o gc.o lex.o parse.o ptree.o spew.o typeck.o cvt.o \
!  edsel.o except.o init.o method.o search.o tree.o xref.o repo.o \
!  bounds.o
  
  # Language-independent object files.
  OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
