Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
R
riscv-gcc-1
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
riscv-gcc-1
Commits
235cfbc4
Commit
235cfbc4
authored
Nov 24, 2000
by
Bernd Schmidt
Committed by
Bernd Schmidt
Nov 24, 2000
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Overhaul sequence point warnings (again)
From-SVN: r37706
parent
58ecb5e2
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
416 additions
and
200 deletions
+416
-200
gcc/ChangeLog
+14
-0
gcc/Makefile.in
+1
-1
gcc/c-common.c
+345
-195
gcc/fold-const.c
+6
-2
gcc/testsuite/ChangeLog
+4
-0
gcc/testsuite/gcc.dg/sequence-pt-1.c
+46
-2
No files found.
gcc/ChangeLog
View file @
235cfbc4
...
@@ -3,6 +3,20 @@
...
@@ -3,6 +3,20 @@
* combine.c (cant_combine_insn_p): New function.
* combine.c (cant_combine_insn_p): New function.
(try_combine): Use it.
(try_combine): Use it.
* Makefile.in (c-common.o): Depend on $(OBSTACK_H).
* c-common.c (c-obstack.c): Include "obstack.h".
(struct reverse_tree): Delete.
(reverse_list, reverse_max_depth): Delete.
(build_reverse_tree, common_ancestor, modify_ok): Delete functions.
(struct tlist, struct tlist_cache): New.
(tlist_obstack, tlist_firstobj, warned_ids, save_expr_cache): New.
(add_tlist, merge_tlist, verify_tree, warning_candidate_p,
warn_for_collisions, warn_for_collisions_1, new_tlist): New
static functions.
(verify_sequence_points): Rewritten.
* fold-const.c (fold): Don't lose possibly important sequence
points when removing one arm of TRUTH_ORIF_EXPRs or TRUTH_ANDIF_EXPRs.
2000-11-24 Richard Sandiford <rsandifo@redhat.com>
2000-11-24 Richard Sandiford <rsandifo@redhat.com>
* gcc/cse.c (cse_insn): Removed conversion of REG_EQUIV to REG_EQUAL
* gcc/cse.c (cse_insn): Removed conversion of REG_EQUIV to REG_EQUAL
...
...
gcc/Makefile.in
View file @
235cfbc4
...
@@ -1214,7 +1214,7 @@ s-under: $(GCC_PASSES)
...
@@ -1214,7 +1214,7 @@ s-under: $(GCC_PASSES)
# A file used by all variants of C.
# A file used by all variants of C.
c-common.o
:
c-common.c $(CONFIG_H) system.h $(TREE_H)
\
c-common.o
:
c-common.c $(CONFIG_H) system.h $(TREE_H)
$(OBSTACK_H)
\
$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H)
\
$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H)
\
$(EXPR_H) diagnostic.h
$(EXPR_H) diagnostic.h
...
...
gcc/c-common.c
View file @
235cfbc4
...
@@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
...
@@ -33,6 +33,7 @@ Boston, MA 02111-1307, USA. */
#include "tm_p.h"
#include "tm_p.h"
#include "intl.h"
#include "intl.h"
#include "diagnostic.h"
#include "diagnostic.h"
#include "obstack.h"
#if USE_CPPLIB
#if USE_CPPLIB
#include "cpplib.h"
#include "cpplib.h"
...
@@ -3414,108 +3415,372 @@ convert_and_check (type, expr)
...
@@ -3414,108 +3415,372 @@ convert_and_check (type, expr)
return
t
;
return
t
;
}
}
/* Describe a reversed version of a normal tree, so that we can get to the
/* A node in a list that describes references to variables (EXPR), which are
parent of each node. */
either read accesses if WRITER is zero, or write accesses, in which case
struct
reverse_tree
WRITER is the parent of EXPR. */
struct
tlist
{
{
/* All reverse_tree structures for a given tree are chained through this
struct
tlist
*
next
;
field. */
tree
expr
,
writer
;
struct
reverse_tree
*
next
;
/* The parent of this node. */
struct
reverse_tree
*
parent
;
/* The actual tree node. */
tree
x
;
/* The operand number this node corresponds to in the parent. */
int
operandno
;
/* Describe whether this expression is written to or read. */
char
read
,
write
;
};
};
/* A list of all reverse_tree structures for a given expression, built by
/* Used to implement a cache the results of a call to verify_tree. We only
build_reverse_tree. */
use this for SAVE_EXPRs. */
static
struct
reverse_tree
*
reverse_list
;
struct
tlist_cache
/* The maximum depth of a tree, computed by build_reverse_tree. */
{
static
int
reverse_max_depth
;
struct
tlist_cache
*
next
;
struct
tlist
*
cache_before_sp
;
struct
tlist
*
cache_after_sp
;
tree
expr
;
};
static
void
build_reverse_tree
PARAMS
((
tree
,
struct
reverse_tree
*
,
int
,
int
,
/* Obstack to use when allocating tlist structures, and corresponding
int
,
int
));
firstobj. */
static
struct
reverse_tree
*
common_ancestor
PARAMS
((
struct
reverse_tree
*
,
static
struct
obstack
tlist_obstack
;
struct
reverse_tree
*
,
static
char
*
tlist_firstobj
=
0
;
struct
reverse_tree
**
,
struct
reverse_tree
**
));
/* Keep track of the identifiers we've warned about, so we can avoid duplicate
static
int
modify_ok
PARAMS
((
struct
reverse_tree
*
,
struct
reverse_tree
*
));
warnings. */
static
struct
tlist
*
warned_ids
;
/* SAVE_EXPRs need special treatment. We process them only once and then
cache the results. */
static
struct
tlist_cache
*
save_expr_cache
;
static
void
add_tlist
PARAMS
((
struct
tlist
**
,
struct
tlist
*
,
tree
,
int
));
static
void
merge_tlist
PARAMS
((
struct
tlist
**
,
struct
tlist
*
,
int
));
static
void
verify_tree
PARAMS
((
tree
,
struct
tlist
**
,
struct
tlist
**
,
tree
));
static
int
warning_candidate_p
PARAMS
((
tree
));
static
void
warn_for_collisions
PARAMS
((
struct
tlist
*
));
static
void
warn_for_collisions_1
PARAMS
((
tree
,
tree
,
struct
tlist
*
,
int
));
static
struct
tlist
*
new_tlist
PARAMS
((
struct
tlist
*
,
tree
,
tree
));
static
void
verify_sequence_points
PARAMS
((
tree
));
static
void
verify_sequence_points
PARAMS
((
tree
));
/* Recursively process an expression, X, building a reverse tree while
/* Create a new struct tlist and fill in its fields. */
descending and recording OPERANDNO, READ, and WRITE in the created
static
struct
tlist
*
structures. DEPTH is used to compute reverse_max_depth.
new_tlist
(
next
,
t
,
writer
)
FIXME: if walk_tree gets moved out of the C++ front end, this should
struct
tlist
*
next
;
probably use walk_tree. */
tree
t
;
tree
writer
;
{
struct
tlist
*
l
;
l
=
(
struct
tlist
*
)
obstack_alloc
(
&
tlist_obstack
,
sizeof
*
l
);
l
->
next
=
next
;
l
->
expr
=
t
;
l
->
writer
=
writer
;
return
l
;
}
/* Add duplicates of the nodes found in ADD to the list *TO. If EXCLUDE_WRITER
is nonnull, we ignore any node we find which has a writer equal to it. */
static
void
static
void
build_reverse_tree
(
x
,
parent
,
operandno
,
read
,
write
,
depth
)
add_tlist
(
to
,
add
,
exclude_writer
,
copy
)
tree
x
;
struct
tlist
**
to
;
struct
reverse_tree
*
parent
;
struct
tlist
*
add
;
int
operandno
,
read
,
write
,
depth
;
tree
exclude_writer
;
int
copy
;
{
{
struct
reverse_tree
*
node
;
while
(
add
)
{
struct
tlist
*
next
=
add
->
next
;
if
(
!
copy
)
add
->
next
=
*
to
;
if
(
!
exclude_writer
||
add
->
writer
!=
exclude_writer
)
*
to
=
copy
?
new_tlist
(
*
to
,
add
->
expr
,
add
->
writer
)
:
add
;
add
=
next
;
}
}
/* Merge the nodes of ADD into TO. This merging process is done so that for
each variable that already exists in TO, no new node is added; however if
there is a write access recorded in ADD, and an occurrence on TO is only
a read access, then the occurrence in TO will be modified to record the
write. */
static
void
merge_tlist
(
to
,
add
,
copy
)
struct
tlist
**
to
;
struct
tlist
*
add
;
int
copy
;
{
struct
tlist
**
end
=
to
;
while
(
*
end
)
end
=
&
(
*
end
)
->
next
;
if
(
x
==
0
||
x
==
error_mark_node
)
while
(
add
)
{
int
found
=
0
;
struct
tlist
*
tmp2
;
struct
tlist
*
next
=
add
->
next
;
for
(
tmp2
=
*
to
;
tmp2
;
tmp2
=
tmp2
->
next
)
if
(
tmp2
->
expr
==
add
->
expr
)
{
found
=
1
;
if
(
!
tmp2
->
writer
)
tmp2
->
writer
=
add
->
writer
;
}
if
(
!
found
)
{
*
end
=
copy
?
add
:
new_tlist
(
NULL
,
add
->
expr
,
add
->
writer
);
end
=
&
(
*
end
)
->
next
;
*
end
=
0
;
}
add
=
next
;
}
}
/* WRITTEN is a variable, WRITER is its parent. Warn if any of the variable
references in list LIST conflict with it, excluding reads if ONLY writers
is nonzero. */
static
void
warn_for_collisions_1
(
written
,
writer
,
list
,
only_writes
)
tree
written
,
writer
;
struct
tlist
*
list
;
int
only_writes
;
{
struct
tlist
*
tmp
;
/* Avoid duplicate warnings. */
for
(
tmp
=
warned_ids
;
tmp
;
tmp
=
tmp
->
next
)
if
(
tmp
->
expr
==
written
)
return
;
return
;
node
=
(
struct
reverse_tree
*
)
xmalloc
(
sizeof
(
struct
reverse_tree
));
while
(
list
)
{
if
(
list
->
expr
==
written
&&
list
->
writer
!=
writer
&&
(
!
only_writes
||
list
->
writer
))
{
warned_ids
=
new_tlist
(
warned_ids
,
written
,
NULL_TREE
);
warning
(
"operation on `%s' may be undefined"
,
IDENTIFIER_POINTER
(
DECL_NAME
(
list
->
expr
)));
}
list
=
list
->
next
;
}
}
/* Given a list LIST of references to variables, find whether any of these
can cause conflicts due to missing sequence points. */
node
->
parent
=
parent
;
static
void
node
->
x
=
x
;
warn_for_collisions
(
list
)
node
->
read
=
read
;
struct
tlist
*
list
;
node
->
write
=
write
;
{
node
->
operandno
=
operandno
;
struct
tlist
*
tmp
;
node
->
next
=
reverse_list
;
reverse_list
=
node
;
if
(
depth
>
reverse_max_depth
)
reverse_max_depth
=
depth
;
switch
(
TREE_CODE
(
x
)
)
for
(
tmp
=
list
;
tmp
;
tmp
=
tmp
->
next
)
{
{
if
(
tmp
->
writer
)
warn_for_collisions_1
(
tmp
->
expr
,
tmp
->
writer
,
list
,
0
);
}
}
/* Return nonzero if X is a tree that can be verified by the sequence poitn
warnings. */
static
int
warning_candidate_p
(
x
)
tree
x
;
{
return
TREE_CODE
(
x
)
==
VAR_DECL
||
TREE_CODE
(
x
)
==
PARM_DECL
;
}
/* 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
expression or its only operand forces a sequence point, then everything up
to the sequence point is stored in PBEFORE_SP. Everything else gets stored
in PNO_SP.
Once we return, we will have emitted warnings if any subexpression before
such a sequence point could be undefined. On a higher level, however, the
sequence point may not be relevant, and we'll merge the two lists.
Example: (b++, a) + b;
The call that processes the COMPOUND_EXPR will store the increment of B
in PBEFORE_SP, and the use of A in PNO_SP. The higher-level call that
processes the PLUS_EXPR will need to merge the two lists so that
eventually, all accesses end up on the same list (and we'll warn about the
unordered subexpressions b++ and b.
A note on merging. If we modify the former example so that our expression
becomes
(b++, b) + a
care must be taken not simply to add all three expressions into the final
PNO_SP list. The function merge_tlist takes care of that by merging the
before-SP list of the COMPOUND_EXPR into its after-SP list in a special
way, so that no more than one access to B is recorded. */
static
void
verify_tree
(
x
,
pbefore_sp
,
pno_sp
,
writer
)
tree
x
;
struct
tlist
**
pbefore_sp
,
**
pno_sp
;
tree
writer
;
{
struct
tlist
*
tmp_before
,
*
tmp_nosp
,
*
tmp_list2
,
*
tmp_list3
;
enum
tree_code
code
;
char
class
;
restart
:
code
=
TREE_CODE
(
x
);
class
=
TREE_CODE_CLASS
(
code
);
if
(
warning_candidate_p
(
x
))
{
*
pno_sp
=
new_tlist
(
*
pno_sp
,
x
,
writer
);
return
;
}
switch
(
code
)
{
case
COMPOUND_EXPR
:
case
TRUTH_ANDIF_EXPR
:
case
TRUTH_ORIF_EXPR
:
tmp_before
=
tmp_nosp
=
tmp_list3
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
0
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
warn_for_collisions
(
tmp_nosp
);
merge_tlist
(
pbefore_sp
,
tmp_before
,
0
);
merge_tlist
(
pbefore_sp
,
tmp_nosp
,
0
);
verify_tree
(
TREE_OPERAND
(
x
,
1
),
&
tmp_list3
,
pno_sp
,
NULL_TREE
);
merge_tlist
(
pbefore_sp
,
tmp_list3
,
0
);
return
;
case
COND_EXPR
:
tmp_before
=
tmp_list2
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
0
),
&
tmp_before
,
&
tmp_list2
,
NULL_TREE
);
warn_for_collisions
(
tmp_list2
);
merge_tlist
(
pbefore_sp
,
tmp_before
,
0
);
merge_tlist
(
pbefore_sp
,
tmp_list2
,
1
);
tmp_list3
=
tmp_nosp
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
1
),
&
tmp_list3
,
&
tmp_nosp
,
NULL_TREE
);
warn_for_collisions
(
tmp_nosp
);
merge_tlist
(
pbefore_sp
,
tmp_list3
,
0
);
tmp_list3
=
tmp_list2
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
2
),
&
tmp_list3
,
&
tmp_list2
,
NULL_TREE
);
warn_for_collisions
(
tmp_list2
);
merge_tlist
(
pbefore_sp
,
tmp_list3
,
0
);
/* Rather than add both tmp_nosp and tmp_list2, we have to merge the
two first, to avoid warning for (a ? b++ : b++). */
merge_tlist
(
&
tmp_nosp
,
tmp_list2
,
0
);
add_tlist
(
pno_sp
,
tmp_nosp
,
NULL_TREE
,
0
);
return
;
case
PREDECREMENT_EXPR
:
case
PREDECREMENT_EXPR
:
case
PREINCREMENT_EXPR
:
case
PREINCREMENT_EXPR
:
case
POSTDECREMENT_EXPR
:
case
POSTDECREMENT_EXPR
:
case
POSTINCREMENT_EXPR
:
case
POSTINCREMENT_EXPR
:
build_reverse_tree
(
TREE_OPERAND
(
x
,
0
),
node
,
0
,
1
,
1
,
depth
+
1
);
verify_tree
(
TREE_OPERAND
(
x
,
0
),
pno_sp
,
pno_sp
,
x
);
break
;
return
;
case
MODIFY_EXPR
:
tmp_before
=
tmp_nosp
=
tmp_list3
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
1
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
verify_tree
(
TREE_OPERAND
(
x
,
0
),
&
tmp_list3
,
&
tmp_list3
,
x
);
/* Expressions inside the LHS are not ordered wrt. the sequence points
in the RHS. Example:
*a = (a++, 2)
Despite the fact that the modification of "a" is in the before_sp
list (tmp_before), it conflicts with the use of "a" in the LHS.
We can handle this by adding the contents of tmp_list3
to those of tmp_before, and redoing the collision warnings for that
list. */
add_tlist
(
&
tmp_before
,
tmp_list3
,
x
,
1
);
warn_for_collisions
(
tmp_before
);
/* Exclude the LHS itself here; we first have to merge it into the
tmp_nosp list. This is done to avoid warning for "a = a"; if we
didn't exclude the LHS, we'd get it twice, once as a read and once
as a write. */
add_tlist
(
pno_sp
,
tmp_list3
,
x
,
0
);
warn_for_collisions_1
(
TREE_OPERAND
(
x
,
0
),
x
,
tmp_nosp
,
1
);
merge_tlist
(
pbefore_sp
,
tmp_before
,
0
);
if
(
warning_candidate_p
(
TREE_OPERAND
(
x
,
0
)))
merge_tlist
(
&
tmp_nosp
,
new_tlist
(
NULL
,
TREE_OPERAND
(
x
,
0
),
x
),
0
);
add_tlist
(
pno_sp
,
tmp_nosp
,
NULL_TREE
,
1
);
return
;
case
CALL_EXPR
:
case
CALL_EXPR
:
build_reverse_tree
(
TREE_OPERAND
(
x
,
0
),
node
,
0
,
1
,
0
,
depth
+
1
);
/* We need to warn about conflicts among arguments and conflicts between
x
=
TREE_OPERAND
(
x
,
1
);
args and the function address. Side effects of the function address,
while
(
x
)
however, are not ordered by the sequence point of the call. */
{
tmp_before
=
tmp_nosp
=
tmp_list2
=
tmp_list3
=
0
;
build_reverse_tree
(
TREE_VALUE
(
x
),
node
,
1
,
1
,
0
,
depth
+
1
);
verify_tree
(
TREE_OPERAND
(
x
,
0
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
x
=
TREE_CHAIN
(
x
);
if
(
TREE_OPERAND
(
x
,
1
))
}
verify_tree
(
TREE_OPERAND
(
x
,
1
),
&
tmp_list2
,
&
tmp_list3
,
NULL_TREE
);
break
;
merge_tlist
(
&
tmp_list3
,
tmp_list2
,
0
);
add_tlist
(
&
tmp_before
,
tmp_list3
,
NULL_TREE
,
0
);
add_tlist
(
&
tmp_before
,
tmp_nosp
,
NULL_TREE
,
0
);
warn_for_collisions
(
tmp_before
);
add_tlist
(
pbefore_sp
,
tmp_before
,
NULL_TREE
,
0
);
return
;
case
TREE_LIST
:
case
TREE_LIST
:
/* Scan all the list, e.g. indices of multi dimensional array. */
/* Scan all the list, e.g. indices of multi dimensional array. */
while
(
x
)
while
(
x
)
{
{
build_reverse_tree
(
TREE_VALUE
(
x
),
node
,
0
,
1
,
0
,
depth
+
1
);
tmp_before
=
tmp_nosp
=
0
;
verify_tree
(
TREE_VALUE
(
x
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
merge_tlist
(
&
tmp_nosp
,
tmp_before
,
0
);
add_tlist
(
pno_sp
,
tmp_nosp
,
NULL_TREE
,
0
);
x
=
TREE_CHAIN
(
x
);
x
=
TREE_CHAIN
(
x
);
}
}
break
;
return
;
case
MODIFY_EXPR
:
case
SAVE_EXPR
:
build_reverse_tree
(
TREE_OPERAND
(
x
,
0
),
node
,
0
,
0
,
1
,
depth
+
1
);
{
build_reverse_tree
(
TREE_OPERAND
(
x
,
1
),
node
,
1
,
1
,
0
,
depth
+
1
);
struct
tlist_cache
*
t
;
for
(
t
=
save_expr_cache
;
t
;
t
=
t
->
next
)
if
(
t
->
expr
==
x
)
break
;
break
;
if
(
!
t
)
{
t
=
(
struct
tlist_cache
*
)
obstack_alloc
(
&
tlist_obstack
,
sizeof
*
t
);
t
->
next
=
save_expr_cache
;
t
->
expr
=
x
;
save_expr_cache
=
t
;
tmp_before
=
tmp_nosp
=
0
;
verify_tree
(
TREE_OPERAND
(
x
,
0
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
warn_for_collisions
(
tmp_nosp
);
tmp_list3
=
0
;
while
(
tmp_nosp
)
{
struct
tlist
*
t
=
tmp_nosp
;
tmp_nosp
=
t
->
next
;
merge_tlist
(
&
tmp_list3
,
t
,
0
);
}
t
->
cache_before_sp
=
tmp_before
;
t
->
cache_after_sp
=
tmp_list3
;
}
merge_tlist
(
pbefore_sp
,
t
->
cache_before_sp
,
1
);
add_tlist
(
pno_sp
,
t
->
cache_after_sp
,
NULL_TREE
,
1
);
return
;
}
default
:
default
:
switch
(
TREE_CODE_CLASS
(
TREE_CODE
(
x
)))
break
;
}
if
(
class
==
'1'
)
{
if
(
first_rtl_op
(
code
)
==
0
)
return
;
x
=
TREE_OPERAND
(
x
,
0
);
writer
=
0
;
goto
restart
;
}
switch
(
class
)
{
{
case
'r'
:
case
'r'
:
case
'<'
:
case
'<'
:
case
'2'
:
case
'2'
:
case
'b'
:
case
'b'
:
case
'1'
:
case
'e'
:
case
'e'
:
case
's'
:
case
's'
:
case
'x'
:
case
'x'
:
...
@@ -3523,84 +3788,15 @@ build_reverse_tree (x, parent, operandno, read, write, depth)
...
@@ -3523,84 +3788,15 @@ build_reverse_tree (x, parent, operandno, read, write, depth)
int
lp
;
int
lp
;
int
max
=
first_rtl_op
(
TREE_CODE
(
x
));
int
max
=
first_rtl_op
(
TREE_CODE
(
x
));
for
(
lp
=
0
;
lp
<
max
;
lp
++
)
for
(
lp
=
0
;
lp
<
max
;
lp
++
)
build_reverse_tree
(
TREE_OPERAND
(
x
,
lp
),
node
,
lp
,
1
,
0
,
{
depth
+
1
);
tmp_before
=
tmp_nosp
=
0
;
break
;
verify_tree
(
TREE_OPERAND
(
x
,
lp
),
&
tmp_before
,
&
tmp_nosp
,
NULL_TREE
);
}
merge_tlist
(
&
tmp_nosp
,
tmp_before
,
0
);
default
:
add_tlist
(
pno_sp
,
tmp_nosp
,
NULL_TREE
,
0
);
break
;
}
}
break
;
break
;
}
}
}
/* Given nodes P1 and P2 as well as enough scratch space pointed to by TMP1
and TMP2, find the common ancestor of P1 and P2. */
static
struct
reverse_tree
*
common_ancestor
(
p1
,
p2
,
tmp1
,
tmp2
)
struct
reverse_tree
*
p1
,
*
p2
;
struct
reverse_tree
**
tmp1
,
**
tmp2
;
{
struct
reverse_tree
*
t1
=
p1
;
struct
reverse_tree
*
t2
=
p2
;
int
i
,
j
;
/* First, check if we're actually looking at the same expression twice,
which can happen if it's wrapped in a SAVE_EXPR - in this case there's
no chance of conflict. */
while
(
t1
&&
t2
&&
t1
->
x
==
t2
->
x
)
{
if
(
TREE_CODE
(
t1
->
x
)
==
SAVE_EXPR
)
return
0
;
t1
=
t1
->
parent
;
t2
=
t2
->
parent
;
}
for
(
i
=
0
;
p1
;
i
++
,
p1
=
p1
->
parent
)
tmp1
[
i
]
=
p1
;
for
(
j
=
0
;
p2
;
j
++
,
p2
=
p2
->
parent
)
tmp2
[
j
]
=
p2
;
while
(
tmp1
[
i
-
1
]
==
tmp2
[
j
-
1
])
i
--
,
j
--
;
return
tmp1
[
i
];
}
/* Subroutine of verify_sequence_points to check whether a node T corresponding
to a MODIFY_EXPR invokes undefined behaviour. OTHER occurs somewhere in the
RHS, and an identical expression is the LHS of T.
For MODIFY_EXPRs, some special cases apply when testing for undefined
behaviour if one of the expressions we found is the LHS of the MODIFY_EXPR.
If the other expression is just a use, then there's no undefined behaviour.
Likewise, if the other expression is wrapped inside another expression that
will force a sequence point, then there's no undefined behaviour either. */
static
int
modify_ok
(
t
,
other
)
struct
reverse_tree
*
t
,
*
other
;
{
struct
reverse_tree
*
p
;
if
(
!
other
->
write
)
return
1
;
/* See if there's an intervening sequence point. */
for
(
p
=
other
;
p
->
parent
!=
t
;
p
=
p
->
parent
)
{
if
((
TREE_CODE
(
p
->
parent
->
x
)
==
COMPOUND_EXPR
||
TREE_CODE
(
p
->
parent
->
x
)
==
TRUTH_ANDIF_EXPR
||
TREE_CODE
(
p
->
parent
->
x
)
==
TRUTH_ORIF_EXPR
||
TREE_CODE
(
p
->
parent
->
x
)
==
COND_EXPR
)
&&
p
->
operandno
==
0
)
return
1
;
if
(
TREE_CODE
(
p
->
parent
->
x
)
==
SAVE_EXPR
)
return
1
;
if
(
TREE_CODE
(
p
->
parent
->
x
)
==
CALL_EXPR
&&
p
->
operandno
!=
0
)
return
1
;
}
}
return
0
;
}
}
/* Try to warn for undefined behaviour in EXPR due to missing sequence
/* Try to warn for undefined behaviour in EXPR due to missing sequence
...
@@ -3610,65 +3806,19 @@ static void
...
@@ -3610,65 +3806,19 @@ static void
verify_sequence_points
(
expr
)
verify_sequence_points
(
expr
)
tree
expr
;
tree
expr
;
{
{
struct
reverse_tree
**
tmp1
,
**
tmp2
;
struct
tlist
*
before_sp
=
0
,
*
after_sp
=
0
;
struct
reverse_tree
*
p
;
reverse_list
=
0
;
reverse_max_depth
=
0
;
build_reverse_tree
(
expr
,
NULL
,
0
,
1
,
0
,
1
);
tmp1
=
(
struct
reverse_tree
**
)
xmalloc
(
sizeof
(
struct
reverse_tree
*
)
*
reverse_max_depth
);
tmp2
=
(
struct
reverse_tree
**
)
xmalloc
(
sizeof
(
struct
reverse_tree
*
)
*
reverse_max_depth
);
/* Search for multiple occurrences of the same variable, where either both
occurrences are writes, or one is a read and a write. If we can't prove
that these are ordered by a sequence point, warn that the expression is
undefined. */
for
(
p
=
reverse_list
;
p
;
p
=
p
->
next
)
{
struct
reverse_tree
*
p2
;
if
(
TREE_CODE
(
p
->
x
)
!=
VAR_DECL
&&
TREE_CODE
(
p
->
x
)
!=
PARM_DECL
)
continue
;
for
(
p2
=
p
->
next
;
p2
;
p2
=
p2
->
next
)
{
if
((
TREE_CODE
(
p2
->
x
)
==
VAR_DECL
||
TREE_CODE
(
p2
->
x
)
==
PARM_DECL
)
&&
DECL_NAME
(
p
->
x
)
==
DECL_NAME
(
p2
->
x
)
&&
(
p
->
write
||
p2
->
write
))
{
struct
reverse_tree
*
t
=
common_ancestor
(
p
,
p2
,
tmp1
,
tmp2
);
if
(
t
==
0
warned_ids
=
0
;
||
TREE_CODE
(
t
->
x
)
==
COMPOUND_EXPR
save_expr_cache
=
0
;
||
TREE_CODE
(
t
->
x
)
==
TRUTH_ANDIF_EXPR
if
(
tlist_firstobj
==
0
)
||
TREE_CODE
(
t
->
x
)
==
TRUTH_ORIF_EXPR
||
TREE_CODE
(
t
->
x
)
==
COND_EXPR
)
continue
;
if
(
TREE_CODE
(
t
->
x
)
==
MODIFY_EXPR
&&
p
->
parent
==
t
&&
modify_ok
(
t
,
p2
))
continue
;
if
(
TREE_CODE
(
t
->
x
)
==
MODIFY_EXPR
&&
p2
->
parent
==
t
&&
modify_ok
(
t
,
p
))
continue
;
warning
(
"operation on `%s' may be undefined"
,
IDENTIFIER_POINTER
(
DECL_NAME
(
p
->
x
)));
break
;
}
}
}
while
(
reverse_list
)
{
{
struct
reverse_tree
*
p
=
reverse_list
;
gcc_obstack_init
(
&
tlist_obstack
);
reverse_list
=
p
->
next
;
tlist_firstobj
=
obstack_alloc
(
&
tlist_obstack
,
0
);
free
(
p
);
}
}
free
(
tmp1
);
free
(
tmp2
);
verify_tree
(
expr
,
&
before_sp
,
&
after_sp
,
0
);
warn_for_collisions
(
after_sp
);
obstack_free
(
&
tlist_obstack
,
tlist_firstobj
);
}
}
void
void
...
...
gcc/fold-const.c
View file @
235cfbc4
...
@@ -5962,7 +5962,9 @@ fold (expr)
...
@@ -5962,7 +5962,9 @@ fold (expr)
/* If either arg is constant true, drop it. */
/* If either arg is constant true, drop it. */
if
(
TREE_CODE
(
arg0
)
==
INTEGER_CST
&&
!
integer_zerop
(
arg0
))
if
(
TREE_CODE
(
arg0
)
==
INTEGER_CST
&&
!
integer_zerop
(
arg0
))
return
non_lvalue
(
convert
(
type
,
arg1
));
return
non_lvalue
(
convert
(
type
,
arg1
));
if
(
TREE_CODE
(
arg1
)
==
INTEGER_CST
&&
!
integer_zerop
(
arg1
))
if
(
TREE_CODE
(
arg1
)
==
INTEGER_CST
&&
!
integer_zerop
(
arg1
)
/* Preserve sequence points. */
&&
(
code
!=
TRUTH_ANDIF_EXPR
||
!
TREE_SIDE_EFFECTS
(
arg0
)))
return
non_lvalue
(
convert
(
type
,
arg0
));
return
non_lvalue
(
convert
(
type
,
arg0
));
/* If second arg is constant zero, result is zero, but first arg
/* If second arg is constant zero, result is zero, but first arg
must be evaluated. */
must be evaluated. */
...
@@ -6048,7 +6050,9 @@ fold (expr)
...
@@ -6048,7 +6050,9 @@ fold (expr)
/* If either arg is constant zero, drop it. */
/* If either arg is constant zero, drop it. */
if
(
TREE_CODE
(
arg0
)
==
INTEGER_CST
&&
integer_zerop
(
arg0
))
if
(
TREE_CODE
(
arg0
)
==
INTEGER_CST
&&
integer_zerop
(
arg0
))
return
non_lvalue
(
convert
(
type
,
arg1
));
return
non_lvalue
(
convert
(
type
,
arg1
));
if
(
TREE_CODE
(
arg1
)
==
INTEGER_CST
&&
integer_zerop
(
arg1
))
if
(
TREE_CODE
(
arg1
)
==
INTEGER_CST
&&
integer_zerop
(
arg1
)
/* Preserve sequence points. */
&&
(
code
!=
TRUTH_ORIF_EXPR
||
!
TREE_SIDE_EFFECTS
(
arg0
)))
return
non_lvalue
(
convert
(
type
,
arg0
));
return
non_lvalue
(
convert
(
type
,
arg0
));
/* If second arg is constant true, result is true, but we must
/* If second arg is constant true, result is true, but we must
evaluate first arg. */
evaluate first arg. */
...
...
gcc/testsuite/ChangeLog
View file @
235cfbc4
2000-11-24 Bernd Schmidt <bernds@redhat.co.uk>
* gcc.dg/sequence-point-1.c: Add some new tests.
2000-11-24 Nathan Sidwell <nathan@codesourcery.com>
2000-11-24 Nathan Sidwell <nathan@codesourcery.com>
* g++.old-deja/g++.other/vaarg4.C: New test.
* g++.old-deja/g++.other/vaarg4.C: New test.
...
...
gcc/testsuite/gcc.dg/sequence-pt-1.c
View file @
235cfbc4
...
@@ -19,7 +19,7 @@ typedef __SIZE_TYPE__ size_t;
...
@@ -19,7 +19,7 @@ typedef __SIZE_TYPE__ size_t;
void
void
foo
(
int
a
,
int
b
,
int
n
,
int
p
,
int
*
ptr
,
struct
s
*
sptr
,
foo
(
int
a
,
int
b
,
int
n
,
int
p
,
int
*
ptr
,
struct
s
*
sptr
,
int
*
ap
,
int
*
bp
,
int
**
cp
,
char
*
ans
)
int
*
ap
,
int
*
bp
,
int
**
cp
,
char
*
ans
,
int
(
*
fnp
[
8
])(
int
)
)
{
{
int
len
;
int
len
;
...
@@ -44,6 +44,9 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
...
@@ -44,6 +44,9 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
a
=
(
bp
[
a
++
]
=
b
)
+
1
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
bp
[
a
++
]
=
b
)
+
1
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
b
++
*
b
++
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
b
++
*
b
++
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
fnb
(
b
++
,
b
++
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
fnb
(
b
++
,
b
++
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
*
fnp
[
b
++
])
(
b
++
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
*
fnp
[
b
])
(
b
++
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
*
fnp
[
b
++
])
(
b
);
/* { dg-warning "undefined" "sequence point warning" } */
*
ap
=
fnc
(
ap
++
);
/* { dg-warning "undefined" "sequence point warning" } */
*
ap
=
fnc
(
ap
++
);
/* { dg-warning "undefined" "sequence point warning" } */
(
a
+=
b
)
+
(
a
+=
n
);
/* { dg-warning "undefined" "sequence point warning" } */
(
a
+=
b
)
+
(
a
+=
n
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
b
,
b
++
)
+
(
b
++
,
b
);
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
b
,
b
++
)
+
(
b
++
,
b
);
/* { dg-warning "undefined" "sequence point warning" } */
...
@@ -51,10 +54,25 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
...
@@ -51,10 +54,25 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
ap
[
a
+=
1
]
+=
a
;
/* { dg-warning "undefined" "sequence point warning" } */
ap
[
a
+=
1
]
+=
a
;
/* { dg-warning "undefined" "sequence point warning" } */
ap
[
a
++
]
+=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
ap
[
a
++
]
+=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
ap
[
a
+=
1
]
+=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
ap
[
a
+=
1
]
+=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
a
++
,
b
=
a
;
/* { dg-warning "undefined" "sequence point warning" } */
b
=
a
,
a
=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
(
b
++
?
n
:
a
)
+
b
;
/* { dg-warning "undefined" "sequence point warning" } */
b
?
a
=
a
++
:
a
;
/* { dg-warning "undefined" "sequence point warning" } */
b
?
a
:
a
=
a
++
;
/* { dg-warning "undefined" "sequence point warning" } */
b
&&
(
a
=
a
++
);
/* { dg-warning "undefined" "sequence point warning" } */
(
a
=
a
++
)
&&
b
;
/* { dg-warning "undefined" "sequence point warning" } */
b
,
(
a
=
a
++
);
/* { dg-warning "undefined" "sequence point warning" } */
(
a
=
a
++
),
b
;
/* { dg-warning "undefined" "sequence point warning" } */
a
^=
b
^=
a
^=
b
;
/* { dg-warning "undefined" "sequence point warning" } */
a
=
a
;
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
a
++
&&
4
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
a
++
&&
4
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
!
(
a
++
&&
4
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
-
(
a
++
&&
4
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
double
)
(
a
++
&&
4
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
len
=
sprintf
(
ans
,
"%d"
,
len
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
len
=
sprintf
(
ans
,
"%d"
,
len
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
fn
(
a
++
);
/* { dg-bogus "undefined" "sequence point warning" } */
a
=
fn
(
a
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
b
++
,
(
b
+
b
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
(
a
=
b
++
),
(
a
=
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
(
a
=
b
++
),
(
a
=
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
b
++
,
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
b
++
,
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
b
++
&&
b
++
;
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
b
++
&&
b
++
;
/* { dg-bogus "undefined" "bogus sequence point warning" } */
...
@@ -63,4 +81,30 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
...
@@ -63,4 +81,30 @@ foo (int a, int b, int n, int p, int *ptr, struct s *sptr,
a
=
(
b
++
?
a
:
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
a
=
(
b
++
?
a
:
b
++
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
ap
[
a
++
]
+=
bp
[
b
];
/* { dg-bogus "undefined" "bogus sequence point warning" } */
ap
[
a
++
]
+=
bp
[
b
];
/* { dg-bogus "undefined" "bogus sequence point warning" } */
ap
[
a
+=
1
]
+=
1
;
/* { dg-bogus "undefined" "bogus sequence point warning" } */
ap
[
a
+=
1
]
+=
1
;
/* { dg-bogus "undefined" "bogus sequence point warning" } */
*
ptr
<
128
?
*
ptr
++
:
*
(
ptr
+=
2
);
/* { dg-bogus "undefined" "bogus sequence point warning" } */
/* The following will be represented internally with a tree consisting of
many duplicated SAVE_EXPRs. This caused the previous version of the
sequence point warning code to fail by running out of virtual memory. */
a
=
((
b
&
1
?
21
:
0
)
|
(
b
&
2
?
22
:
0
)
|
(
b
&
3
?
23
:
0
)
|
(
b
&
4
?
24
:
0
)
|
(
b
&
5
?
25
:
0
)
|
(
b
&
6
?
26
:
0
)
|
(
b
&
7
?
27
:
0
)
|
(
b
&
8
?
28
:
0
)
|
(
b
&
9
?
29
:
0
)
|
(
b
&
10
?
30
:
0
)
|
(
b
&
11
?
31
:
0
)
|
(
b
&
12
?
32
:
0
)
|
(
b
&
13
?
1
:
0
)
|
(
b
&
14
?
2
:
0
)
|
(
b
&
15
?
3
:
0
)
|
(
b
&
16
?
4
:
0
)
|
(
b
&
17
?
5
:
0
)
|
(
b
&
18
?
6
:
0
)
|
(
b
&
19
?
7
:
0
)
|
(
b
&
20
?
8
:
0
)
|
(
b
&
21
?
9
:
0
));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment