This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
New feature, warning on n=n++ etc.
- To: egcs-patches at cygnus dot com
- Subject: New feature, warning on n=n++ etc.
- From: Michael Meeks <michael at imaginator dot com>
- Date: Tue, 16 Jun 1998 21:13:04 +0100 (BST)
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));
+
+
+