This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Fix middle-end/13448
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 29 Feb 2004 15:42:40 -0800
- Subject: PATCH: Fix middle-end/13448
- Reply-to: mark at codesourcery dot com
This patch fixes a problem where we tried to inline a function
containing erroneous code. Doing so caused us to crash later because
the inliner replaced a const parameter with a constant -- and the
erroneous code tried to modify the constant.
There were two issues: (a) we tried to inline after encountering
erroneous code, and (b) we considered modifying a const variable just
a warning in C. That latter is wildly out of sync with current
practice; it's a holdover from the "const is just a hint" mindset of
ten years ago. Nowadays the compiler makes all kinds of assumptions
based on the const-ness of variables, and we should not be accepting
code that tries to modify const variables -- we'll likely generate
silently wrong code.
As for (a), just as we don't generate code after issuing an error
message, so should we not try to inline after issuing an error
message. After an error, our goal should be to go quickly through the
rest of the code, issuing more errors, so that the user can fix all of
the problems. There's no point in optimizing.
There's a minor kink in that not inlining means that we will fail to
issue -Winlining messages, but that's a small price to pay for (a)
faster compilation, and (b) fewer crashes.
Tested on i686-pc-linux-gnu, applied on the mainline and on the 3.4
branch.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2004-02-27 Mark Mitchell <mark@codesourcery.com>
PR middle-end/13448
* c-tree.h (readonly_warning): Rename to ...
(readonly_error): ... this.
* c-typeck.c (build_unary_op): Adjust accordingly.
(readonly_warning): Rename to ...
(readonly_error): ... this and issue errors, not warnings.
(build_modify_expr): Call readonly_error, not readonly_warning.
(c_expand_asm_operands): Likewise.
* tree-inline.c (optimize_inline_calls): Do not inline functions
after errors have occurred.
2004-02-29 Mark Mitchell <mark@codesourcery.com>
PR middle-end/13448
* gcc.dg/inline-5.c: New test.
* gcc.dg/always-inline.c: Split out tests into ...
* gcc.dg/always-inline2.c: ... this and ...
* gcc.dg/always-inline3.c: ... this.
Index: c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.136
diff -c -5 -p -r1.136 c-tree.h
*** c-tree.h 3 Dec 2003 23:33:48 -0000 1.136
--- c-tree.h 29 Feb 2004 23:25:16 -0000
*************** extern tree build_component_ref (tree, t
*** 266,276 ****
extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree build_external_ref (tree, int);
extern tree parser_build_binary_op (enum tree_code, tree, tree);
extern int c_tree_expr_nonnegative_p (tree);
! extern void readonly_warning (tree, const char *);
extern tree build_conditional_expr (tree, tree, tree);
extern tree build_compound_expr (tree);
extern tree c_cast_expr (tree, tree);
extern tree build_c_cast (tree, tree);
extern tree build_modify_expr (tree, enum tree_code, tree);
--- 266,276 ----
extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree build_external_ref (tree, int);
extern tree parser_build_binary_op (enum tree_code, tree, tree);
extern int c_tree_expr_nonnegative_p (tree);
! extern void readonly_error (tree, const char *);
extern tree build_conditional_expr (tree, tree, tree);
extern tree build_compound_expr (tree);
extern tree c_cast_expr (tree, tree);
extern tree build_c_cast (tree, tree);
extern tree build_modify_expr (tree, enum tree_code, tree);
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.272.2.1
diff -c -5 -p -r1.272.2.1 c-typeck.c
*** c-typeck.c 5 Feb 2004 22:01:29 -0000 1.272.2.1
--- c-typeck.c 29 Feb 2004 23:25:16 -0000
*************** build_unary_op (enum tree_code code, tre
*** 2418,2431 ****
: "invalid lvalue in decrement")))
return error_mark_node;
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
! readonly_warning (arg,
! ((code == PREINCREMENT_EXPR
! || code == POSTINCREMENT_EXPR)
! ? "increment" : "decrement"));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
else
val = build (code, TREE_TYPE (arg), arg, inc);
--- 2418,2431 ----
: "invalid lvalue in decrement")))
return error_mark_node;
/* Report a read-only lvalue. */
if (TREE_READONLY (arg))
! readonly_error (arg,
! ((code == PREINCREMENT_EXPR
! || code == POSTINCREMENT_EXPR)
! ? "increment" : "decrement"));
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
else
val = build (code, TREE_TYPE (arg), arg, inc);
*************** pedantic_lvalue_warning (enum tree_code
*** 2643,2667 ****
}
/* Warn about storing in something that is `const'. */
void
! readonly_warning (tree arg, const char *msgid)
{
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
! readonly_warning (TREE_OPERAND (arg, 0), msgid);
else
! pedwarn ("%s of read-only member `%s'", _(msgid),
! IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
}
else if (TREE_CODE (arg) == VAR_DECL)
! pedwarn ("%s of read-only variable `%s'", _(msgid),
! IDENTIFIER_POINTER (DECL_NAME (arg)));
else
! pedwarn ("%s of read-only location", _(msgid));
}
/* Mark EXP saying that we need to be able to take the
address of it; it should not be allocated in a register.
Returns true if successful. */
--- 2643,2667 ----
}
/* Warn about storing in something that is `const'. */
void
! readonly_error (tree arg, const char *msgid)
{
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
! readonly_error (TREE_OPERAND (arg, 0), msgid);
else
! error ("%s of read-only member `%s'", _(msgid),
! IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
}
else if (TREE_CODE (arg) == VAR_DECL)
! error ("%s of read-only variable `%s'", _(msgid),
! IDENTIFIER_POINTER (DECL_NAME (arg)));
else
! error ("%s of read-only location", _(msgid));
}
/* Mark EXP saying that we need to be able to take the
address of it; it should not be allocated in a register.
Returns true if successful. */
*************** build_modify_expr (tree lhs, enum tree_c
*** 3307,3317 ****
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
! readonly_warning (lhs, "assignment");
/* If storing into a structure or union member,
it has probably been given type `int'.
Compute the type that would go with
the actual amount of storage the member occupies. */
--- 3307,3317 ----
if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
|| ((TREE_CODE (lhstype) == RECORD_TYPE
|| TREE_CODE (lhstype) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (lhstype)))
! readonly_error (lhs, "assignment");
/* If storing into a structure or union member,
it has probably been given type `int'.
Compute the type that would go with
the actual amount of storage the member occupies. */
*************** c_expand_asm_operands (tree string, tree
*** 6331,6341 ****
if (TREE_READONLY (o[i])
|| TYPE_READONLY (type)
|| ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (type)))
! readonly_warning (o[i], "modification by `asm'");
}
}
/* Those MODIFY_EXPRs could do autoincrements. */
emit_queue ();
--- 6331,6341 ----
if (TREE_READONLY (o[i])
|| TYPE_READONLY (type)
|| ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE)
&& C_TYPE_FIELDS_READONLY (type)))
! readonly_error (o[i], "modification by `asm'");
}
}
/* Those MODIFY_EXPRs could do autoincrements. */
emit_queue ();
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.90.4.3
diff -c -5 -p -r1.90.4.3 tree-inline.c
*** tree-inline.c 20 Feb 2004 07:35:40 -0000 1.90.4.3
--- tree-inline.c 29 Feb 2004 23:25:17 -0000
*************** Boston, MA 02111-1307, USA. */
*** 37,47 ****
#include "hashtab.h"
#include "splay-tree.h"
#include "langhooks.h"
#include "cgraph.h"
#include "intl.h"
!
/* This should be eventually be generalized to other languages, but
this would require a shared function-as-trees infrastructure. */
#ifndef INLINER_FOR_JAVA
#include "c-common.h"
--- 37,47 ----
#include "hashtab.h"
#include "splay-tree.h"
#include "langhooks.h"
#include "cgraph.h"
#include "intl.h"
! #include "diagnostic.h"
/* This should be eventually be generalized to other languages, but
this would require a shared function-as-trees infrastructure. */
#ifndef INLINER_FOR_JAVA
#include "c-common.h"
*************** expand_calls_inline (tree *tp, inline_da
*** 1613,1622 ****
--- 1613,1628 ----
void
optimize_inline_calls (tree fn)
{
inline_data id;
tree prev_fn;
+
+ /* There is no point in performing inlining if errors have already
+ occurred -- and we might crash if we try to inline invalid
+ code. */
+ if (errorcount || sorrycount)
+ return;
/* Clear out ID. */
memset (&id, 0, sizeof (id));
id.decl = fn;
Index: testsuite/gcc.dg/always_inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/always_inline.c,v
retrieving revision 1.1
diff -c -5 -p -r1.1 always_inline.c
*** testsuite/gcc.dg/always_inline.c 13 Jan 2004 01:35:26 -0000 1.1
--- testsuite/gcc.dg/always_inline.c 29 Feb 2004 23:25:17 -0000
***************
*** 1,20 ****
/* { dg-do compile } */
/* { dg-options "-Winline -O2" } */
#include <stdarg.h>
- inline __attribute__ ((always_inline)) void t(void); /* { dg-error "body not available" "" } */
- void
- q(void)
- {
- t(); /* { dg-error "called from here" "" } */
- }
- inline __attribute__ ((always_inline)) void
- q2(void)
- { /* { dg-error "recursive" "" } */
- q2(); /* { dg-error "called from here" "" } */
- q2(); /* { dg-error "called from here" "" } */
- }
inline __attribute__ ((always_inline)) void
e(int t, ...)
{ /* { dg-error "variable argument" "" } */
va_list q;
va_start (q, t);
--- 1,8 ----
Index: testsuite/gcc.dg/inline-5.c
===================================================================
RCS file: testsuite/gcc.dg/inline-5.c
diff -N testsuite/gcc.dg/inline-5.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/inline-5.c 29 Feb 2004 23:32:40 -0000
***************
*** 0 ****
--- 1,13 ----
+ /* PR middle-end/13448 */
+
+ /* { dg-options "-O3" } */
+
+ void funct (const int n)
+ {
+ n++; /* { dg-error "" } */
+ }
+
+ int main () {
+ funct (1);
+ return 0;
+ }
Index: testsuite/gcc.dg/always_inline2.c
===================================================================
RCS file: testsuite/gcc.dg/always_inline2.c
diff -N testsuite/gcc.dg/always_inline2.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/always_inline2.c 29 Feb 2004 23:34:16 -0000
***************
*** 0 ****
--- 1,8 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Winline -O2" } */
+ inline __attribute__ ((always_inline)) void t(void); /* { dg-error "body not available" "" } */
+ void
+ q(void)
+ {
+ t(); /* { dg-error "called from here" "" } */
+ }
Index: testsuite/gcc.dg/always_inline3.c
===================================================================
RCS file: testsuite/gcc.dg/always_inline3.c
diff -N testsuite/gcc.dg/always_inline3.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.dg/always_inline3.c 29 Feb 2004 23:34:16 -0000
***************
*** 0 ****
--- 1,8 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Winline -O2" } */
+ inline __attribute__ ((always_inline)) void
+ q2(void)
+ { /* { dg-error "recursive" "" } */
+ q2(); /* { dg-error "called from here" "" } */
+ q2(); /* { dg-error "called from here" "" } */
+ }