This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[4.5] PR c/c++/16202 The -Wsequence-point warning misses many important instances
- From: "Manuel López-Ibáñez" <lopezibanez at gmail dot com>
- To: "Gcc Patch List" <gcc-patches at gcc dot gnu dot org>
- Cc: "Tom Truscott" <Tom dot Truscott at sas dot com>
- Date: Fri, 24 Oct 2008 19:19:48 +0200
- Subject: [4.5] PR c/c++/16202 The -Wsequence-point warning misses many important instances
The idea behind this patch was proposed by Tom Truscott. It fixes many
(all?) cases where -Wsequence-points failed.
I am submitting this now in case anyone wants to comment and to have
link from bugzilla.
Bootstrapped and regression tested on x86_64-unknown-linux-gnu with
--enable-languages=all
2008-10-24 Manuel López-Ibáñez <manu@gcc.gnu.org>
PR 16202
* c-typeck.c (lvalue_p): Move declaration ...
* c-common.h (lvalue_p): ... to here.
* c-common.c (candidate_equal_p): New.
(add_tlist): Use it.
(merge_tlist): Use it.
(warn_for_collisions_1): Likewise.
(warning_candidate_p): Accept more candidates.
(verify_tree): A warning candidate can be an expression. Use
candidate_equal_p.
testsuite/
* gcc.dg/sequence-pt-1.c: Remove XFAILs.
* gcc.dg/sequence-pt-2.c: New.
* gcc.dg/sequence-pt-3.c: New.
* g++.dg/warn/sequence-pt-1.C: Remove XFAILs.
* g++.dg/warn/sequence-pt-2.c: New.
* g++.dg/warn/sequence-pt-3.c: New.
Index: gcc/testsuite/gcc.dg/sequence-pt-1.c
===================================================================
--- gcc/testsuite/gcc.dg/sequence-pt-1.c (revision 141322)
+++ gcc/testsuite/gcc.dg/sequence-pt-1.c (working copy)
@@ -28,14 +28,14 @@ foo (int a, int b, int n, int p, int *pt
a = ++a + b; /* { dg-warning "undefined" "sequence point warning" } */
a = a-- + b; /* { dg-warning "undefined" "sequence point warning" } */
ap[n] = bp[n++]; /* { dg-warning "undefined" "sequence point warning" } */
ap[--n] = bp[n]; /* { dg-warning "undefined" "sequence point warning" } */
ap[++n] = bp[--n]; /* { dg-warning "undefined" "sequence point warning" } */
- cp[n][n] = cp[n][n]++; /* { dg-warning "undefined" "sequence point warning" { xfail *-*-* } } */
+ cp[n][n] = cp[n][n]++; /* { dg-warning "undefined" "sequence point warning" } */
cp[n][p] = cp[n][n++]; /* { dg-warning "undefined" "sequence point warning" } */
*ptr++ = (size_t)ptr++; /* { dg-warning "undefined" "sequence point warning" } */
- sptr->a = sptr->a++; /* { dg-warning "undefined" "sequence point warning" { xfail *-*-* } } */
+ sptr->a = sptr->a++; /* { dg-warning "undefined" "sequence point warning" } */
sptr->a = (size_t)(sptr++); /* { dg-warning "undefined" "sequence point warning" } */
*ptr++ = fn (*ptr); /* { dg-warning "undefined" "sequence point warning" } */
a = b = a++; /* { dg-warning "undefined" "sequence point warning" } */
b = a = --b; /* { dg-warning "undefined" "sequence point warning" } */
a = 1 + (a = 1); /* { dg-warning "undefined" "sequence point warning" } */
Index: gcc/testsuite/gcc.dg/sequence-pt-3.c
===================================================================
--- gcc/testsuite/gcc.dg/sequence-pt-3.c (revision 0)
+++ gcc/testsuite/gcc.dg/sequence-pt-3.c (revision 0)
@@ -0,0 +1,15 @@
+/* More sequence point warning tests */
+/* { dg-do compile } */
+/* { dg-options "-Wsequence-point" } */
+
+void bar(int i, int j)
+{
+ return;
+}
+
+void foo (int i)
+{
+ int a = i-i++; (void)a; /* { dg-warning "undefined" "sequence point warning" } */
+
+ bar (i--, i++); /* { dg-warning "undefined" "sequence point warning" } */
+}
Index: gcc/testsuite/gcc.dg/sequence-pt-2.c
===================================================================
--- gcc/testsuite/gcc.dg/sequence-pt-2.c (revision 0)
+++ gcc/testsuite/gcc.dg/sequence-pt-2.c (revision 0)
@@ -0,0 +1,46 @@
+/* More sequence point warning tests */
+/* { dg-do compile } */
+/* { dg-options "-Wsequence-point" } */
+
+struct s { struct s *nxt; int v; } q;
+
+int x[10];
+
+int foo(int *p)
+{
+ int i = 0;
+
+ /* Test general-lvalue sequence point warnings */
+ (*p) = (*p)++; /* { dg-warning "undefined" "sequence point warning" } */
+ p[3] = p[3]++; /* { dg-warning "undefined" "sequence point warning" } */
+ p[i] = p[i]++; /* { dg-warning "undefined" "sequence point warning" } */
+ x[3] = x[3]++; /* { dg-warning "undefined" "sequence point warning" } */
+ q.nxt->nxt->v = q.nxt->nxt->v++; /* { dg-warning "undefined" "sequence point warning" } */
+
+ /* test expressions that appear elsewhere in the C grammar */
+
+ { int a = i-i++; (void)a;} /* { dg-warning "undefined" "sequence point warning" } */
+
+ if ((i-i++) != 0) /* { dg-warning "undefined" "sequence point warning" } */
+ return i-i++; /* { dg-warning "undefined" "sequence point warning" } */
+
+ for (i-i++;;) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ for (; (i-i++) != 0; ) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ for (;;i-i++) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ while ((i-i++) != 0) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ do {} while ((i-i++) != 0); /* { dg-warning "undefined" "sequence point warning" } */
+
+ switch (i-i++) { /* { dg-warning "undefined" "sequence point warning" } */
+ case 0: return 1;
+ }
+
+ return 0;
+}
Index: gcc/testsuite/g++.dg/warn/sequence-pt-1.C
===================================================================
--- gcc/testsuite/g++.dg/warn/sequence-pt-1.C (revision 141322)
+++ gcc/testsuite/g++.dg/warn/sequence-pt-1.C (working copy)
@@ -28,14 +28,14 @@ foo (int a, int b, int n, int p, int *pt
a = ++a + b; /* { dg-warning "undefined" "sequence point warning" } */
a = a-- + b; /* { dg-warning "undefined" "sequence point warning" } */
ap[n] = bp[n++]; /* { dg-warning "undefined" "sequence point warning" } */
ap[--n] = bp[n]; /* { dg-warning "undefined" "sequence point warning" } */
ap[++n] = bp[--n]; /* { dg-warning "undefined" "sequence point warning" } */
- cp[n][n] = cp[n][n]++; /* { dg-warning "undefined" "sequence point warning" { xfail *-*-* } } */
+ cp[n][n] = cp[n][n]++; /* { dg-warning "undefined" "sequence point warning" } */
cp[n][p] = cp[n][n++]; /* { dg-warning "undefined" "sequence point warning" } */
*ptr++ = (size_t)ptr++; /* { dg-warning "undefined" "sequence point warning" } */
- sptr->a = sptr->a++; /* { dg-warning "undefined" "sequence point warning" { xfail *-*-* } } */
+ sptr->a = sptr->a++; /* { dg-warning "undefined" "sequence point warning" } */
sptr->a = (size_t)(sptr++); /* { dg-warning "undefined" "sequence point warning" } */
*ptr++ = fn (*ptr); /* { dg-warning "undefined" "sequence point warning" } */
a = b = a++; /* { dg-warning "undefined" "sequence point warning" } */
b = a = --b; /* { dg-warning "undefined" "sequence point warning" } */
a = 1 + (a = 1); /* { dg-warning "undefined" "sequence point warning" } */
Index: gcc/testsuite/g++.dg/warn/sequence-pt-2.c
===================================================================
--- gcc/testsuite/g++.dg/warn/sequence-pt-2.c (revision 0)
+++ gcc/testsuite/g++.dg/warn/sequence-pt-2.c (revision 0)
@@ -0,0 +1,46 @@
+/* More sequence point warning tests */
+/* { dg-do compile } */
+/* { dg-options "-Wsequence-point" } */
+
+struct s { struct s *nxt; int v; } q;
+
+int x[10];
+
+int foo(int *p)
+{
+ int i = 0;
+
+ /* Test general-lvalue sequence point warnings */
+ (*p) = (*p)++; /* { dg-warning "undefined" "sequence point warning" } */
+ p[3] = p[3]++; /* { dg-warning "undefined" "sequence point warning" } */
+ p[i] = p[i]++; /* { dg-warning "undefined" "sequence point warning" } */
+ x[3] = x[3]++; /* { dg-warning "undefined" "sequence point warning" } */
+ q.nxt->nxt->v = q.nxt->nxt->v++; /* { dg-warning "undefined" "sequence point warning" } */
+
+ /* test expressions that appear elsewhere in the C grammar */
+
+ { int a = i-i++; (void)a;} /* { dg-warning "undefined" "sequence point warning" } */
+
+ if ((i-i++) != 0) /* { dg-warning "undefined" "sequence point warning" } */
+ return i-i++; /* { dg-warning "undefined" "sequence point warning" } */
+
+ for (i-i++;;) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ for (; (i-i++) != 0; ) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ for (;;i-i++) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ while ((i-i++) != 0) /* { dg-warning "undefined" "sequence point warning" } */
+ ;
+
+ do {} while ((i-i++) != 0); /* { dg-warning "undefined" "sequence point warning" } */
+
+ switch (i-i++) { /* { dg-warning "undefined" "sequence point warning" } */
+ case 0: return 1;
+ }
+
+ return 0;
+}
Index: gcc/testsuite/g++.dg/warn/sequence-pt-3.c
===================================================================
--- gcc/testsuite/g++.dg/warn/sequence-pt-3.c (revision 0)
+++ gcc/testsuite/g++.dg/warn/sequence-pt-3.c (revision 0)
@@ -0,0 +1,15 @@
+/* More sequence point warning tests */
+/* { dg-do compile } */
+/* { dg-options "-Wsequence-point" } */
+
+void bar(int i, int j)
+{
+ return;
+}
+
+void foo (int i)
+{
+ int a = i-i++; (void)a; /* { dg-warning "undefined" "sequence point warning" } */
+
+ bar (i--, i++); /* { dg-warning "undefined" "sequence point warning" } */
+}
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c (revision 141322)
+++ gcc/c-typeck.c (working copy)
@@ -101,11 +101,10 @@ static void add_pending_init (tree, tree
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
static void readonly_error (tree, enum lvalue_use);
static int lvalue_or_else (const_tree, enum lvalue_use);
-static int lvalue_p (const_tree);
static void record_maybe_used_decl (tree);
static int comptypes_internal (const_tree, const_tree);
/* Return true if EXP is a null pointer constant, false otherwise. */
@@ -3256,11 +3255,11 @@ build_unary_op (location_t location,
/* Return nonzero if REF is an lvalue valid for this language.
Lvalues can be assigned, unless their type has TYPE_READONLY.
Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
-static int
+int
lvalue_p (const_tree ref)
{
const enum tree_code code = TREE_CODE (ref);
switch (code)
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c (revision 141322)
+++ gcc/c-common.c (working copy)
@@ -1828,10 +1828,11 @@ static struct tlist_cache *save_expr_cac
static void add_tlist (struct tlist **, struct tlist *, tree, int);
static void merge_tlist (struct tlist **, struct tlist *, int);
static void verify_tree (tree, struct tlist **, struct tlist **, tree);
static int warning_candidate_p (tree);
+static int candidate_equal_p (tree, tree);
static void warn_for_collisions (struct tlist *);
static void warn_for_collisions_1 (tree, tree, struct tlist *, int);
static struct tlist *new_tlist (struct tlist *, tree, tree);
/* Create a new struct tlist and fill in its fields. */
@@ -1855,11 +1856,11 @@ add_tlist (struct tlist **to, struct tli
while (add)
{
struct tlist *next = add->next;
if (!copy)
add->next = *to;
- if (!exclude_writer || add->writer != exclude_writer)
+ if (!exclude_writer || !candidate_equal_p (add->writer, exclude_writer))
*to = copy ? new_tlist (*to, add->expr, add->writer) : add;
add = next;
}
}
@@ -1882,11 +1883,11 @@ merge_tlist (struct tlist **to, struct t
int found = 0;
struct tlist *tmp2;
struct tlist *next = add->next;
for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
- if (tmp2->expr == add->expr)
+ if (candidate_equal_p (tmp2->expr, add->expr))
{
found = 1;
if (!tmp2->writer)
tmp2->writer = add->writer;
}
@@ -1910,19 +1911,18 @@ warn_for_collisions_1 (tree written, tre
{
struct tlist *tmp;
/* Avoid duplicate warnings. */
for (tmp = warned_ids; tmp; tmp = tmp->next)
- if (tmp->expr == written)
+ if (candidate_equal_p (tmp->expr, written))
return;
while (list)
{
- if (list->expr == written
- && list->writer != writer
- && (!only_writes || list->writer)
- && DECL_NAME (list->expr))
+ if (candidate_equal_p (list->expr, written)
+ && !candidate_equal_p (list->writer, writer)
+ && (!only_writes || list->writer))
{
warned_ids = new_tlist (warned_ids, written, NULL_TREE);
warning_at (EXPR_HAS_LOCATION (writer)
? EXPR_LOCATION (writer) : input_location,
OPT_Wsequence_point, "operation on %qE may be undefined",
@@ -1950,11 +1950,21 @@ warn_for_collisions (struct tlist *list)
/* Return nonzero if X is a tree that can be verified by the sequence point
warnings. */
static int
warning_candidate_p (tree x)
{
- return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
+ /* !VOID_TYPE_P (TREE_TYPE (x)) is workaround for cp/tree.c
+ (lvalue_p) crash on TRY/CATCH. */
+ return !(DECL_P (x) && DECL_ARTIFICIAL (x))
+ && TREE_TYPE (x) && !VOID_TYPE_P (TREE_TYPE (x)) && lvalue_p (x);
+}
+
+/* Return nonzero if X and Y appear to be the same candidate (or NULL) */
+static int
+candidate_equal_p (tree x, tree y)
+{
+ return (x == y) || (x && y && operand_equal_p (x, y, 0));
}
/* Walk the tree X, and record accesses to variables. If X is written by the
parent tree, WRITER is the parent.
We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP. If this
@@ -1996,14 +2006,11 @@ verify_tree (tree x, struct tlist **pbef
restart:
code = TREE_CODE (x);
cl = TREE_CODE_CLASS (code);
if (warning_candidate_p (x))
- {
- *pno_sp = new_tlist (*pno_sp, x, writer);
- return;
- }
+ *pno_sp = new_tlist (*pno_sp, x, writer);
switch (code)
{
case CONSTRUCTOR:
return;
@@ -2112,11 +2119,11 @@ verify_tree (tree x, struct tlist **pbef
case SAVE_EXPR:
{
struct tlist_cache *t;
for (t = save_expr_cache; t; t = t->next)
- if (t->expr == x)
+ if (candidate_equal_p (t->expr, x))
break;
if (!t)
{
t = XOBNEW (&tlist_obstack, struct tlist_cache);
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h (revision 141322)
+++ gcc/c-common.h (working copy)
@@ -848,10 +848,11 @@ extern tree finish_label_address_expr (t
/* Same function prototype, but the C and C++ front ends have
different implementations. Used in c-common.c. */
extern tree lookup_label (tree);
extern tree lookup_name (tree);
+extern int lvalue_p (const_tree);
extern bool vector_targets_convertible_p (const_tree t1, const_tree t2);
extern bool vector_types_convertible_p (const_tree t1, const_tree t2, bool emit_lax_note);
extern rtx c_expand_expr (tree, rtx, enum machine_mode, int, rtx *);