aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index ed22592..fa7a396 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see
#include "calls.h"
#include "tree-vector-builder.h"
#include "tree-ssa-strlen.h"
+#include "varasm.h"
enum strlen_range_kind {
/* Compute the exact constant string length. */
@@ -1280,7 +1281,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
c_strlen_data *pdata, unsigned eltsize)
{
gcc_assert (TREE_CODE (arg) != SSA_NAME);
-
+
/* The length computed by this invocation of the function. */
tree val = NULL_TREE;
@@ -1422,7 +1423,44 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
type about the length here. */
tight_bound = true;
}
- else if (VAR_P (arg))
+ else if (TREE_CODE (arg) == MEM_REF
+ && TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == INTEGER_TYPE
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == ADDR_EXPR)
+ {
+ /* Handle a MEM_REF into a DECL accessing an array of integers,
+ being conservative about references to extern structures with
+ flexible array members that can be initialized to arbitrary
+ numbers of elements as an extension (static structs are okay).
+ FIXME: Make this less conservative -- see
+ component_ref_size in tree.c. */
+ tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+ if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
+ && (decl_binds_to_current_def_p (ref)
+ || !array_at_struct_end_p (arg)))
+ {
+ /* Fail if the offset is out of bounds. Such accesses
+ should be diagnosed at some point. */
+ val = DECL_SIZE_UNIT (ref);
+ if (!val || integer_zerop (val))
+ return false;
+
+ poly_offset_int psiz = wi::to_offset (val);
+ poly_offset_int poff = mem_ref_offset (arg);
+ if (known_le (psiz, poff))
+ return false;
+
+ pdata->minlen = ssize_int (0);
+
+ /* Subtract the offset and one for the terminating nul. */
+ psiz -= poff;
+ psiz -= 1;
+ val = wide_int_to_tree (TREE_TYPE (val), psiz);
+ /* Since VAL reflects the size of a declared object
+ rather the type of the access it is not a tight bound. */
+ }
+ }
+ else if (TREE_CODE (arg) == PARM_DECL || VAR_P (arg))
{
/* Avoid handling pointers to arrays. GCC might misuse
a pointer to an array of one bound to point to an array
@@ -1500,7 +1538,8 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
the referenced subobject minus 1 (for the terminating nul). */
tree type = TREE_TYPE (base);
if (TREE_CODE (type) == POINTER_TYPE
- || !VAR_P (base) || !(val = DECL_SIZE_UNIT (base)))
+ || (TREE_CODE (base) != PARM_DECL && !VAR_P (base))
+ || !(val = DECL_SIZE_UNIT (base)))
val = build_all_ones_cst (size_type_node);
else
{