diff options
author | Richard Kenner <kenner@gcc.gnu.org> | 1995-01-28 15:14:09 -0500 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 1995-01-28 15:14:09 -0500 |
commit | abe80e6df576bbb5c1f6bcc545c0546f80056f59 (patch) | |
tree | d8ec2b6ed43d2e35a15b9f77a2f2375b8f8ef4ee | |
parent | da6f15cdef9251ed945e2435e12aa3713cf0d808 (diff) | |
download | gcc-abe80e6df576bbb5c1f6bcc545c0546f80056f59.zip gcc-abe80e6df576bbb5c1f6bcc545c0546f80056f59.tar.gz gcc-abe80e6df576bbb5c1f6bcc545c0546f80056f59.tar.bz2 |
(c_expand_return): Refine check for returning pointer to local
variable to allow subtracting a pointer from it.
From-SVN: r8837
-rw-r--r-- | gcc/c-typeck.c | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index b295be7..ceabea8 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -1,5 +1,5 @@ /* Build expressions with type checking for C compiler. - Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc. + Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc. This file is part of GNU CC. @@ -6348,25 +6348,50 @@ c_expand_return (retval) /* Strip any conversions, additions, and subtractions, and see if we are returning the address of a local variable. Warn if so. */ - while (TREE_CODE (inner) == NOP_EXPR - || TREE_CODE (inner) == NON_LVALUE_EXPR - || TREE_CODE (inner) == CONVERT_EXPR - || TREE_CODE (inner) == PLUS_EXPR - || TREE_CODE (inner) == MINUS_EXPR) - inner = TREE_OPERAND (inner, 0); - - if (TREE_CODE (inner) == ADDR_EXPR) + while (1) { - inner = TREE_OPERAND (inner, 0); + switch (TREE_CODE (inner)) + { + case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR: + case PLUS_EXPR: + inner = TREE_OPERAND (inner, 0); + continue; + + case MINUS_EXPR: + /* If the second operand of the MINUS_EXPR has a pointer + type (or is converted from it), this may be valid, so + don't give a warning. */ + { + tree op1 = TREE_OPERAND (inner, 1); + + while (! POINTER_TYPE_P (TREE_TYPE (op1)) + && (TREE_CODE (op1) == NOP_EXPR + || TREE_CODE (op1) == NON_LVALUE_EXPR + || TREE_CODE (op1) == CONVERT_EXPR)) + op1 = TREE_OPERAND (op1, 0); + + if (POINTER_TYPE_P (TREE_TYPE (op1))) + break; - while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r') - inner = TREE_OPERAND (inner, 0); + inner = TREE_OPERAND (inner, 0); + continue; + } + + case ADDR_EXPR: + inner = TREE_OPERAND (inner, 0); - if (TREE_CODE (inner) == VAR_DECL - && ! DECL_EXTERNAL (inner) - && ! TREE_STATIC (inner) - && DECL_CONTEXT (inner) == current_function_decl) - warning ("function returns address of local variable"); + while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r') + inner = TREE_OPERAND (inner, 0); + + if (TREE_CODE (inner) == VAR_DECL + && ! DECL_EXTERNAL (inner) + && ! TREE_STATIC (inner) + && DECL_CONTEXT (inner) == current_function_decl) + warning ("function returns address of local variable"); + break; + } + + break; } t = build (MODIFY_EXPR, TREE_TYPE (res), res, t); |