This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

New feature, warning on n=n++ etc.



Hi,

	A first attempt, at a first submission to egcs. I have signed a
copyright assignment, posted it to RMS and recieved a reply confirming
this.

	The feature is to catch probably undefined syntax. The following
cases are flagged, where Fail denotes a warning.

  a = a++ ; /* Fail */
  a = --a ; /* Fail */
  a = ++a + b ; /* Fail */
  a = a-- + b ; /* Fail */
  a = (a++ && 4) ; /* shouldn't Fail but does */
  a[n]=b[n++] ; /* Fail */
  a[--n]=b[n] ; /* Fail */
  a[++n]=b[--n] ; /* Fail */
  c[n][n]=c[n][n]++ ; /* should fail but doesn't */
  c[n][p]=c[n][n++] ; /* Fail */ /* if [n][n] then fails twice */
  *ptr++ = (int)ptr++ ; /* Fail */
  ptr->a = ptr->a++ ; /* should fail but doesn't */
  ptr->a = (int)(ptr++) ; /* Fail */
  len = sprintf (ans, "%d", len++) ;    /* Fail */
  *ptr++ = fn(*ptr) ; /* should fail but doesn't */
  a = b = a++ ;   /* Fail */
  b = a = --b ;   /* Fail */
  a = 1 + (a=1) ; /* Fail */
  a = (a=b) ;     /* Fail */
  a = (a=b) + 1 ; /* Fail */

	A changelog entry might look like : ?

Tue Jun 16 19:41:18 1998  Michael Meeks  (michael@imaginator.com)

	* c-toplev.c: Added -Wundefined to lang_options.
	* c-decl.c (c_decode_option): Added -Wundefined, added warn_undefined
	to -Wall.
	* c-iterate.c (collect_iterators): Broke out operand classification code
	into get_max_tree_operands.
	* tree.c (get_max_tree_operands): Returns max. valid number of operands
	used solely in parse tree.
	* tree.h: appended prototype.
	* c-typeck.c (build_modify_expr): Added call to check_modify_expr
	(check_modify_expr): Created, checks and warns for some undefined syntax.


	I hope this is useful,

	Regards,

		Michael Meeks.

-- 
 michael@imaginator.com  <><, Pseudo Engineer, itinerant idiot
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/c-decl.c oldgcc/c-decl.c
*** gcc/c-decl.c	Mon Feb  9 21:15:13 1998
--- oldgcc/c-decl.c	Tue Jun 16 19:54:10 1998
***************
*** 558,567 ****
--- 558,569 ----
  
  int warn_sign_compare = -1;
  
  /* Nonzero means `$' can be in an identifier.  */
  
+ int warn_undefined = 0 ;
+ 
  #ifndef DOLLARS_IN_IDENTIFIERS
  #define DOLLARS_IN_IDENTIFIERS 1
  #endif
  int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
  
***************
*** 710,719 ****
--- 712,723 ----
      warn_parentheses = 0;
    else if (!strcmp (p, "-Wreturn-type"))
      warn_return_type = 1;
    else if (!strcmp (p, "-Wno-return-type"))
      warn_return_type = 0;
+   else if (!strcmp(p, "-Wundefined"))
+     warn_undefined = 1 ;
    else if (!strcmp (p, "-Wcomment"))
      ; /* cpp handles this one.  */
    else if (!strcmp (p, "-Wno-comment"))
      ; /* cpp handles this one.  */
    else if (!strcmp (p, "-Wcomments"))
***************
*** 756,765 ****
--- 760,770 ----
        warn_unused = 1;
        warn_switch = 1;
        warn_format = 1;
        warn_char_subscripts = 1;
        warn_parentheses = 1;
+       warn_undefined = 1;
        warn_missing_braces = 1;
        /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn
  	 it off only if it's not explicit.  */
        warn_main = 2;
      }
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/c-iterate.c oldgcc/c-iterate.c
*** gcc/c-iterate.c	Mon Aug 11 16:57:03 1997
--- oldgcc/c-iterate.c	Tue Jun 16 19:54:10 1998
***************
*** 236,264 ****
  						       list));
  
  	case 'e':
  	case 'r':
  	  {
! 	    int num_args = tree_code_length[(int) TREE_CODE (exp)];
  	    int i;
  
- 	    /* Some tree codes have RTL, not trees, as operands.  */
- 	    switch (TREE_CODE (exp))
- 	      {
- 	      case CALL_EXPR:
- 		num_args = 2;
- 		break;
- 	      case METHOD_CALL_EXPR:
- 		num_args = 3;
- 		break;
- 	      case WITH_CLEANUP_EXPR:
- 		num_args = 1;
- 		break;
- 	      case RTL_EXPR:
- 		return list;
- 	      }
- 		
  	    for (i = 0; i < num_args; i++)
  	      list = collect_iterators (TREE_OPERAND (exp, i), list);
  	    return list;
  	  }
  	default:
--- 236,249 ----
  						       list));
  
  	case 'e':
  	case 'r':
  	  {
! 	    /* Some tree codes have RTL, not trees, as operands.  */
! 	    int num_args = get_max_tree_operands (exp) ;
  	    int i;
  
  	    for (i = 0; i < num_args; i++)
  	      list = collect_iterators (TREE_OPERAND (exp, i), list);
  	    return list;
  	  }
  	default:
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/c-tree.h oldgcc/c-tree.h
*** gcc/c-tree.h	Mon Aug 11 16:57:03 1997
--- oldgcc/c-tree.h	Tue Jun 16 19:54:10 1998
***************
*** 492,501 ****
--- 492,503 ----
  
  /* Warn about comparison of signed and unsigned values.  */
  
  extern int warn_sign_compare;
  
+ extern int warn_undefined;
+ 
  /* Nonzero means this is a function to call to perform comptypes
     on two record types.  */
  
  extern int (*comptypes_record_hook) ();
  
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/c-typeck.c oldgcc/c-typeck.c
*** gcc/c-typeck.c	Sat Sep 27 04:46:33 1997
--- oldgcc/c-typeck.c	Tue Jun 16 21:08:57 1998
***************
*** 3804,3813 ****
--- 3804,3918 ----
      value = non_lvalue (value);
  
    return value;
  }
  
+ /* Recursive Check for un-defined sytax, note lhs && rhs have
+    no meaning ! ie. n++=n ; is equaly invalid to n=n++ ; */
+ void
+ check_modify_expr (lhs, rhs)
+      tree lhs, rhs;
+ {
+ tree identifierName ;   /* a VAR_DECL name on the lhs, that could
+ 			   be the same as one on the rhs */
+ identifierName = NULL_TREE ;
+ 
+ if (lhs == NULL_TREE || rhs == NULL_TREE)
+   return ;
+ 
+ /*fprintf (stderr, "Check modify expr in '%s', line '%d' : '%s' = '%s'\n",input_filename, lineno, tree_code_name[TREE_CODE(lhs)], tree_code_name[TREE_CODE(rhs)]) ;*/
+ 
+ switch (TREE_CODE(rhs))
+   {
+   case (VAR_DECL):
+     identifierName = DECL_NAME(rhs) ;
+     break;	  
+   case PREDECREMENT_EXPR:
+   case PREINCREMENT_EXPR:
+   case POSTDECREMENT_EXPR:
+   case POSTINCREMENT_EXPR:
+     {
+       tree var_decl = TREE_OPERAND(rhs,0) ;
+       if (TREE_CODE(var_decl)==VAR_DECL)
+ 	identifierName=DECL_NAME(var_decl) ;
+     }
+   break ;
+   case TREE_LIST:
+     {
+       tree parm = TREE_CHAIN(rhs) ;
+       int lp = 0 ;
+       /* Now scan all the list. eg. indices of multi dimensional array */
+       while (parm)
+ 	{
+ 	  check_modify_expr(lhs, TREE_VALUE(parm)) ;
+ 	  parm = TREE_CHAIN(parm) ;
+ 	}
+     }
+     return ;
+   case NOP_EXPR:
+     return ;
+   case MODIFY_EXPR:
+     /* First check for form a = b = a++ by checking rhs */
+     check_modify_expr (lhs, TREE_OPERAND(rhs, 1)) ;
+     /* Then check for a = (a = 1) + 2 */
+     identifierName = DECL_NAME(TREE_OPERAND(rhs,0)) ;
+     break ;
+   default: /* We don't know what to do... pray check_modify_expr removes loops in the tree */
+     switch (TREE_CODE_CLASS(TREE_CODE(rhs)))
+       {
+       case 'r':
+       case '<':	
+       case '2':
+       case 'b':
+       case '1':
+       case 'e':
+       case 's':
+       case 'x':
+ 	{
+ 	  int lp ;
+ 	  int max = get_max_tree_operands(rhs) ;
+ 	  for (lp=0;lp<max;lp++)
+ 	    check_modify_expr(lhs, TREE_OPERAND(rhs,lp)) ;
+ 	  return ;
+ 	}
+       default:
+ 	return ;
+       }
+     break ;
+   }
+ if (identifierName != NULL_TREE)
+   {
+     switch (TREE_CODE(lhs))
+       {
+ 	/* perhaps this variable was incremented on the rhs */
+       case VAR_DECL:
+ 	if (TREE_CODE(rhs)!=VAR_DECL)
+ 	  if (DECL_NAME(lhs)==identifierName)
+ 	    warning ("operation on '%s' may be undefined", IDENTIFIER_POINTER(DECL_NAME(lhs))) ;
+ 	break ;
+       case PREDECREMENT_EXPR:
+       case PREINCREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+ 	{
+ 	  tree var_decl = TREE_OPERAND(lhs,0) ;
+ 	  if (TREE_CODE(var_decl)==VAR_DECL)
+ 	    if (identifierName==DECL_NAME(var_decl))
+ 	      warning ("operation on '%s' may be undefined", IDENTIFIER_POINTER(DECL_NAME(var_decl))) ;
+ 	}
+       break ;
+       case NULL_TREE:
+ 	return ;
+       default:
+ 	/* to save duplicating tree traversal code swap args, and recurse */
+ 	check_modify_expr(rhs, lhs) ;
+ 	break ;
+       }
+   }
+ }
+ 
+ 
  /* Build an assignment expression of lvalue LHS from value RHS.
     MODIFYCODE is the code for a binary operator that we use
     to combine the old value of LHS with RHS to get the new value.
     Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.  */
  
***************
*** 3953,3962 ****
--- 4058,4072 ----
  
    newrhs = convert_for_assignment (lhstype, newrhs, "assignment",
  				   NULL_TREE, NULL_TREE, 0);
    if (TREE_CODE (newrhs) == ERROR_MARK)
      return error_mark_node;
+ 
+   if (warn_undefined)
+     check_modify_expr(lhs,rhs) ;
+ 
+   /* Scan operands */
  
    result = build (MODIFY_EXPR, lhstype, lhs, newrhs);
    TREE_SIDE_EFFECTS (result) = 1;
  
    /* If we got the LHS in a different type for storing in,
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/toplev.c oldgcc/toplev.c
*** gcc/toplev.c	Mon Feb  9 00:56:08 1998
--- oldgcc/toplev.c	Tue Jun 16 19:54:10 1998
***************
*** 819,828 ****
--- 819,829 ----
    "-Wno-missing-prototypes",
    "-Wnested-externs",
    "-Wno-nested-externs",
    "-Wparentheses",
    "-Wno-parentheses",
+   "-Wundefined",
    "-Wpointer-arith",
    "-Wno-pointer-arith",
    "-Wredundant-decls",
    "-Wno-redundant-decls",
    "-Wsign-compare",
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/tree.c oldgcc/tree.c
*** gcc/tree.c	Fri Nov 14 14:30:00 1997
--- oldgcc/tree.c	Tue Jun 16 19:54:10 1998
***************
*** 4713,4723 ****
--- 4713,4750 ----
  	  buffer[index] = 1;
  	}
      }
    return non_const_bits;
  }
+ 
+ /* Return the maximum valid number of operands that are used solely for
+   the parse tree. NB. Some tree codes have RTL, not trees, as operands. */
  
+ int
+ get_max_tree_operands (exp)
+ tree exp;
+ {
+   if (exp==NULL_TREE)
+     return 0 ;
+ 
+   switch (TREE_CODE (exp))
+     {
+     case CALL_EXPR:
+       return 2 ;
+     case METHOD_CALL_EXPR:
+       return 3 ;
+     case WITH_CLEANUP_EXPR:
+       return 1 ;
+     case RTL_EXPR:
+       return 0 ;
+     case OP_IDENTIFIER:
+       return 0 ;
+     }
+   
+   return tree_code_length[(int) TREE_CODE(exp)] ;
+ }
+ 
  /* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
     The result is placed in BUFFER (which is an array of bytes).
     If the constructor is constant, NULL_TREE is returned.
     Otherwise, a TREE_LIST of the non-constant elements is emitted.  */
  
diff -C 5 -x *.[ao] -x c-parse.c -x bi-parser.c -x cexp.c -x objc-parse.c -x Makefile -x config.status gcc/tree.h oldgcc/tree.h
*** gcc/tree.h	Wed Oct 15 18:19:40 1997
--- oldgcc/tree.h	Tue Jun 16 19:54:10 1998
***************
*** 1887,1891 ****
--- 1887,1896 ----
  
  /* Output a marker (i.e. a label) for the absolute end of the generated
     code for a function definition.  */
  
  extern void dwarf2out_end_epilogue	PROTO((void));
+ 
+ extern int get_max_tree_operands PROTO((tree));
+ 
+ 
+ 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]