Commit d4bf6975 by Martin Sebor Committed by Jeff Law

gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range rather than set_range_info.

	* gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range
	rather than set_range_info.
	* tree-ssa-strlen.c (set_strlen_range): Extracted from
	maybe_set_strlen_range.  Handle potentially boundary crossing
	cases more conservatively.
	(maybe_set_strlen_range): Parts refactored into set_strlen_range.
	Call set_strlen_range.
	* tree-ssa-strlen.h (set_strlen_range): Add prototype.

	* gcc.dg/strlenopt-36.c: Update.
	* gcc.dg/strlenopt-45.c: Update.
	* gcc.c-torture/execute/strlen-5.c: New test.
	* gcc.c-torture/execute/strlen-6.c: New test.
	* gcc.c-torture/execute/strlen-7.c: New test.

Co-Authored-By: Jeff Law <law@redhat.com>

From-SVN: r267531
parent ec1faddf
2019-01-02 Martin Sebor <msebor@redhat.com>
Jeff Law <law@redhat.com>
* gimple-fold.c (gimple_fold_builtin_strlen): Use set_strlen_range
rather than set_range_info.
* tree-ssa-strlen.c (set_strlen_range): Extracted from
maybe_set_strlen_range. Handle potentially boundary crossing
cases more conservatively.
(maybe_set_strlen_range): Parts refactored into set_strlen_range.
Call set_strlen_range.
* tree-ssa-strlen.h (set_strlen_range): Add prototype.
PR middle-end/88663
* gimple-fold.c (get_range_strlen): Update prototype to no longer
need the flexp argument.
......
......@@ -3739,10 +3739,9 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
return true;
}
/* Set the strlen() range to [0, MAXLEN]. */
if (tree lhs = gimple_call_lhs (stmt))
if (TREE_CODE (lhs) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
set_range_info (lhs, VR_RANGE, minlen, maxlen);
set_strlen_range (lhs, maxlen);
return false;
}
......
2019-01-02 Martin Sebor <msebor@redhat.com>
Jeff Law <law@redhat.com>
* gcc.dg/strlenopt-36.c: Update.
* gcc.dg/strlenopt-45.c: Update.
* gcc.c-torture/execute/strlen-5.c: New test.
* gcc.c-torture/execute/strlen-6.c: New test.
* gcc.c-torture/execute/strlen-7.c: New test.
2019-01-02 Jakub Jelinek <jakub@redhat.com>
PR testsuite/87304
......
/* Test to verify that strlen() calls with conditional expressions
and unterminated arrays or pointers to such things as arguments
are evaluated without making assumptions about array sizes. */
extern __SIZE_TYPE__ strlen (const char *);
unsigned nfails;
#define A(expr, N) \
do { \
const char *_s = (expr); \
unsigned _n = strlen (_s); \
((_n == N) \
? 0 \
: (__builtin_printf ("line %i: strlen ((%s) = (\"%s\"))" \
" == %u failed\n", \
__LINE__, #expr, _s, N), \
++nfails)); \
} while (0)
volatile int i0 = 0;
const char ca[2][3] = { "12" };
const char cb[2][3] = { { '1', '2', '3', }, { '4' } };
char va[2][3] = { "123" };
char vb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
const char *s = "123456";
static void test_binary_cond_expr_global (void)
{
A (i0 ? "1" : ca[0], 2);
A (i0 ? ca[0] : "123", 3);
/* The call to strlen (cb[0]) is strictly undefined because the array
isn't nul-terminated. This test verifies that the strlen range
optimization doesn't assume that the argument is necessarily nul
terminated.
Ditto for strlen (vb[0]). */
A (i0 ? "1" : cb[0], 4); /* GCC 8.2 failure */
A (i0 ? cb[0] : "12", 2);
A (i0 ? "1" : va[0], 3); /* GCC 8.2 failure */
A (i0 ? va[0] : "1234", 4);
A (i0 ? "1" : vb[0], 5); /* GCC 8.2 failure */
A (i0 ? vb[0] : "12", 2);
}
static void test_binary_cond_expr_local (void)
{
const char lca[2][3] = { "12" };
const char lcb[2][3] = { { '1', '2', '3', }, { '4' } };
char lva[2][3] = { "123" };
char lvb[2][3] = { { '1', '2', '3', }, { '4', '5' } };
/* Also undefined as above. */
A (i0 ? "1" : lca[0], 2);
A (i0 ? lca[0] : "123", 3);
A (i0 ? "1" : lcb[0], 4); /* GCC 8.2 failure */
A (i0 ? lcb[0] : "12", 2);
A (i0 ? "1" : lva[0], 3); /* GCC 8.2 failure */
A (i0 ? lva[0] : "1234", 4);
A (i0 ? "1" : lvb[0], 5); /* GCC 8.2 failure */
A (i0 ? lvb[0] : "12", 2);
}
static void test_ternary_cond_expr (void)
{
/* Also undefined. */
A (i0 == 0 ? s : i0 == 1 ? vb[0] : "123", 6);
A (i0 == 0 ? vb[0] : i0 == 1 ? s : "123", 5);
A (i0 == 0 ? "123" : i0 == 1 ? s : vb[0], 3);
}
const char (*pca)[3] = &ca[0];
const char (*pcb)[3] = &cb[0];
char (*pva)[3] = &va[0];
char (*pvb)[3] = &vb[0];
static void test_binary_cond_expr_arrayptr (void)
{
/* Also undefined. */
A (i0 ? *pca : *pcb, 4); /* GCC 8.2 failure */
A (i0 ? *pcb : *pca, 2);
A (i0 ? *pva : *pvb, 5); /* GCC 8.2 failure */
A (i0 ? *pvb : *pva, 3);
}
int main (void)
{
test_binary_cond_expr_global ();
test_binary_cond_expr_local ();
test_ternary_cond_expr ();
test_binary_cond_expr_arrayptr ();
if (nfails)
__builtin_abort ();
}
/* Test to verify that a strlen() call with a pointer to a dynamic type
doesn't make assumptions based on the static type of the original
pointer. See g++.dg/init/strlen.C for the corresponding C++ test. */
struct A { int i; char a[1]; void (*p)(); };
struct B { char a[sizeof (struct A) - __builtin_offsetof (struct A, a)]; };
__attribute__ ((noipa)) void
init (char *d, const char *s)
{
__builtin_strcpy (d, s);
}
struct B b;
__attribute__ ((noipa)) void
test_dynamic_type (struct A *p)
{
/* The following call is undefined because it writes past the end
of the p->a subobject, but the corresponding GIMPLE considers
it valid and there's apparently no way to distinguish invalid
cases from ones like it that might be valid. If/when GIMPLE
changes to make this possible this test can be removed. */
char *q = (char*)__builtin_memcpy (p->a, &b, sizeof b);
init (q, "foobar");
if (6 != __builtin_strlen (q))
__builtin_abort();
}
int main (void)
{
struct A *p = (struct A*)__builtin_malloc (sizeof *p);
test_dynamic_type (p);
return 0;
}
......@@ -9,23 +9,6 @@ extern char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
extern char a0[0]; /* Intentionally not tested here. */
extern char ax[]; /* Same. */
struct MemArrays {
char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
char a0[0]; /* Not tested here. */
};
struct NestedMemArrays {
struct { char a7[7]; } ma7;
struct { char a6[6]; } ma6;
struct { char a5[5]; } ma5;
struct { char a4[4]; } ma4;
struct { char a3[3]; } ma3;
struct { char a2[2]; } ma2;
struct { char a1[1]; } ma1;
struct { char a0[0]; } ma0;
char last;
};
extern void failure_on_line (int);
#define TEST_FAIL(line) \
......@@ -51,36 +34,4 @@ void test_array (void)
T (strlen (a1) == 0); */
}
void test_memarray (struct MemArrays *ma)
{
T (strlen (ma->a7) < sizeof ma->a7);
T (strlen (ma->a6) < sizeof ma->a6);
T (strlen (ma->a5) < sizeof ma->a5);
T (strlen (ma->a4) < sizeof ma->a4);
T (strlen (ma->a3) < sizeof ma->a3);
/* The following two calls are folded too early which defeats
the strlen() optimization.
T (strlen (ma->a2) == 1);
T (strlen (ma->a1) == 0); */
}
/* Verify that the range of strlen(A) of a last struct member is
set even when the array is the sole member of a struct as long
as the struct itself is a member of another struct. The converse
is tested in stlenopt-37.c. */
void test_nested_memarray (struct NestedMemArrays *ma)
{
T (strlen (ma->ma7.a7) < sizeof ma->ma7.a7);
T (strlen (ma->ma6.a6) < sizeof ma->ma6.a6);
T (strlen (ma->ma5.a5) < sizeof ma->ma5.a5);
T (strlen (ma->ma4.a4) < sizeof ma->ma4.a4);
T (strlen (ma->ma3.a3) < sizeof ma->ma3.a3);
/* The following two calls are folded too early which defeats
the strlen() optimization.
T (strlen (ma->ma2.a2) == 1);
T (strlen (ma->ma1.a1) == 0); */
}
/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized" } } */
......@@ -2,7 +2,7 @@
Test to verify that strnlen built-in expansion works correctly
in the absence of tree strlen optimization.
{ dg-do compile }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
{ dg-options "-O2 -Wall -Wno-stringop-overflow -fdump-tree-optimized" } */
#include "strlenopt.h"
......@@ -85,19 +85,19 @@ void elim_strnlen_arr_cst (void)
ELIM (strnlen (a3_7[0], 1) < 2);
ELIM (strnlen (a3_7[0], 2) < 3);
ELIM (strnlen (a3_7[0], 3) < 4);
ELIM (strnlen (a3_7[0], 9) < 8);
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8);
ELIM (strnlen (a3_7[0], SIZE_MAX) < 8);
ELIM (strnlen (a3_7[0], -1) < 8);
ELIM (strnlen (a3_7[0], 9) <= 9);
ELIM (strnlen (a3_7[0], PTRDIFF_MAX) <= sizeof a3_7);
ELIM (strnlen (a3_7[0], SIZE_MAX) <= sizeof a3_7);
ELIM (strnlen (a3_7[0], -1) <= sizeof a3_7);
ELIM (strnlen (a3_7[2], 0) == 0);
ELIM (strnlen (a3_7[2], 1) < 2);
ELIM (strnlen (a3_7[2], 2) < 3);
ELIM (strnlen (a3_7[2], 3) < 4);
ELIM (strnlen (a3_7[2], 9) < 8);
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8);
ELIM (strnlen (a3_7[2], SIZE_MAX) < 8);
ELIM (strnlen (a3_7[2], -1) < 8);
ELIM (strnlen (a3_7[2], 9) <= 9);
ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < sizeof a3_7);
ELIM (strnlen (a3_7[2], SIZE_MAX) < sizeof a3_7);
ELIM (strnlen (a3_7[2], -1) < sizeof a3_7);
ELIM (strnlen ((char*)a3_7, 0) == 0);
ELIM (strnlen ((char*)a3_7, 1) < 2);
......@@ -105,123 +105,19 @@ void elim_strnlen_arr_cst (void)
ELIM (strnlen ((char*)a3_7, 3) < 4);
ELIM (strnlen ((char*)a3_7, 9) < 10);
ELIM (strnlen ((char*)a3_7, 19) < 20);
ELIM (strnlen ((char*)a3_7, 21) < 22);
ELIM (strnlen ((char*)a3_7, 23) < 22);
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22);
ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22);
ELIM (strnlen ((char*)a3_7, -1) < 22);
ELIM (strnlen ((char*)a3_7, 21) <= sizeof a3_7);
ELIM (strnlen ((char*)a3_7, 23) <= sizeof a3_7);
ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) <= sizeof a3_7);
ELIM (strnlen ((char*)a3_7, SIZE_MAX) <= sizeof a3_7);
ELIM (strnlen ((char*)a3_7, -1) <= sizeof a3_7);
ELIM (strnlen (ax, 0) == 0);
ELIM (strnlen (ax, 1) < 2);
ELIM (strnlen (ax, 2) < 3);
ELIM (strnlen (ax, 9) < 10);
ELIM (strnlen (a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
ELIM (strnlen (a3, SIZE_MAX) < PTRDIFF_MAX);
ELIM (strnlen (a3, -1) < PTRDIFF_MAX);
}
struct MemArrays
{
char c;
char a0[0];
char a1[1];
char a3[3];
char a5[5];
char a3_7[3][7];
char ax[1];
};
void elim_strnlen_memarr_cst (struct MemArrays *p, int i)
{
ELIM (strnlen (&p->c, 0) == 0);
ELIM (strnlen (&p->c, 1) < 2);
ELIM (strnlen (&p->c, 9) == 0);
ELIM (strnlen (&p->c, PTRDIFF_MAX) == 0);
ELIM (strnlen (&p->c, SIZE_MAX) == 0);
ELIM (strnlen (&p->c, -1) == 0);
/* Other accesses to internal zero-length arrays are undefined. */
ELIM (strnlen (p->a0, 0) == 0);
ELIM (strnlen (p->a1, 0) == 0);
ELIM (strnlen (p->a1, 1) < 2);
ELIM (strnlen (p->a1, 9) == 0);
ELIM (strnlen (p->a1, PTRDIFF_MAX) == 0);
ELIM (strnlen (p->a1, SIZE_MAX) == 0);
ELIM (strnlen (p->a1, -1) == 0);
ELIM (strnlen (p->a3, 0) == 0);
ELIM (strnlen (p->a3, 1) < 2);
ELIM (strnlen (p->a3, 2) < 3);
ELIM (strnlen (p->a3, 3) < 4);
ELIM (strnlen (p->a3, 9) < 4);
ELIM (strnlen (p->a3, PTRDIFF_MAX) < 4);
ELIM (strnlen (p->a3, SIZE_MAX) < 4);
ELIM (strnlen (p->a3, -1) < 4);
ELIM (strnlen (p[i].a3, 0) == 0);
ELIM (strnlen (p[i].a3, 1) < 2);
ELIM (strnlen (p[i].a3, 2) < 3);
ELIM (strnlen (p[i].a3, 3) < 4);
ELIM (strnlen (p[i].a3, 9) < 4);
ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 4);
ELIM (strnlen (p[i].a3, SIZE_MAX) < 4);
ELIM (strnlen (p[i].a3, -1) < 4);
ELIM (strnlen (p->a3_7[0], 0) == 0);
ELIM (strnlen (p->a3_7[0], 1) < 2);
ELIM (strnlen (p->a3_7[0], 2) < 3);
ELIM (strnlen (p->a3_7[0], 3) < 4);
ELIM (strnlen (p->a3_7[0], 9) < 8);
ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 8);
ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 8);
ELIM (strnlen (p->a3_7[0], -1) < 8);
ELIM (strnlen (p->a3_7[2], 0) == 0);
ELIM (strnlen (p->a3_7[2], 1) < 2);
ELIM (strnlen (p->a3_7[2], 2) < 3);
ELIM (strnlen (p->a3_7[2], 3) < 4);
ELIM (strnlen (p->a3_7[2], 9) < 8);
ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 8);
ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 8);
ELIM (strnlen (p->a3_7[2], -1) < 8);
ELIM (strnlen (p->a3_7[i], 0) == 0);
ELIM (strnlen (p->a3_7[i], 1) < 2);
ELIM (strnlen (p->a3_7[i], 2) < 3);
ELIM (strnlen (p->a3_7[i], 3) < 4);
#if 0
/* This is tranformed into strnlen ((char*)p + offsetof (a3_7[i]), N)
which makes it impssible to determine the size of the array. */
ELIM (strnlen (p->a3_7[i], 9) < 8);
ELIM (strnlen (p->a3_7[i], PTRDIFF_MAX) < 8);
ELIM (strnlen (p->a3_7[i], SIZE_MAX) < 8);
ELIM (strnlen (p->a3_7[i], -1) < 8);
#else
ELIM (strnlen (p->a3_7[i], 9) < 10);
ELIM (strnlen (p->a3_7[i], 19) < 20);
#endif
ELIM (strnlen ((char*)p->a3_7, 0) == 0);
ELIM (strnlen ((char*)p->a3_7, 1) < 2);
ELIM (strnlen ((char*)p->a3_7, 2) < 3);
ELIM (strnlen ((char*)p->a3_7, 3) < 4);
ELIM (strnlen ((char*)p->a3_7, 9) < 10);
ELIM (strnlen ((char*)p->a3_7, 19) < 20);
ELIM (strnlen ((char*)p->a3_7, 21) < 22);
ELIM (strnlen ((char*)p->a3_7, 23) < 22);
ELIM (strnlen ((char*)p->a3_7, PTRDIFF_MAX) < 22);
ELIM (strnlen ((char*)p->a3_7, SIZE_MAX) < 22);
ELIM (strnlen ((char*)p->a3_7, -1) < 22);
ELIM (strnlen (p->ax, 0) == 0);
ELIM (strnlen (p->ax, 1) < 2);
ELIM (strnlen (p->ax, 2) < 3);
ELIM (strnlen (p->ax, 9) < 10);
ELIM (strnlen (p->a3, PTRDIFF_MAX) <= PTRDIFF_MAX);
ELIM (strnlen (p->a3, SIZE_MAX) < PTRDIFF_MAX);
ELIM (strnlen (p->a3, -1) < PTRDIFF_MAX);
ELIM (strnlen (ax, PTRDIFF_MAX) < PTRDIFF_MAX);
ELIM (strnlen (ax, SIZE_MAX) < PTRDIFF_MAX);
ELIM (strnlen (ax, -1) < PTRDIFF_MAX);
}
......
......@@ -1121,67 +1121,23 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
update_stmt (last.stmt);
}
/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
a character array A[N] with unknown length bounded by N, and for
strnlen(), by min (N, BOUND). */
static tree
maybe_set_strlen_range (tree lhs, tree src, tree bound)
/* For an LHS that is an SSA_NAME that is the result of a strlen()
call, or when BOUND is non-null, of a strnlen() call, set LHS
range info to [0, min (MAX, BOUND)] when the range includes more
than one value and return LHS. Otherwise, when the range
[MIN, MAX] is such that MIN == MAX, return the tree representation
of (MIN). The latter allows callers to fold suitable strnlen() calls
to constants. */
tree
set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
{
if (TREE_CODE (lhs) != SSA_NAME
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
return NULL_TREE;
if (TREE_CODE (src) == SSA_NAME)
{
gimple *def = SSA_NAME_DEF_STMT (src);
if (is_gimple_assign (def)
&& gimple_assign_rhs_code (def) == ADDR_EXPR)
src = gimple_assign_rhs1 (def);
}
wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node));
wide_int min = wi::zero (max.get_precision ());
if (TREE_CODE (src) == ADDR_EXPR)
{
/* The last array member of a struct can be bigger than its size
suggests if it's treated as a poor-man's flexible array member. */
src = TREE_OPERAND (src, 0);
bool src_is_array = TREE_CODE (TREE_TYPE (src)) == ARRAY_TYPE;
if (src_is_array
&& TREE_CODE (src) != MEM_REF
&& !array_at_struct_end_p (src))
{
tree type = TREE_TYPE (src);
if (tree size = TYPE_SIZE_UNIT (type))
if (size && TREE_CODE (size) == INTEGER_CST)
max = wi::to_wide (size);
/* For strlen() the upper bound above is equal to
the longest string that can be stored in the array
(i.e., it accounts for the terminating nul. For
strnlen() bump up the maximum by one since the array
need not be nul-terminated. */
if (!bound && max != 0)
--max;
}
else
{
if (TREE_CODE (src) == COMPONENT_REF && !src_is_array)
src = TREE_OPERAND (src, 1);
if (DECL_P (src))
{
/* Handle the unlikely case of strlen (&c) where c is some
variable. */
if (tree size = DECL_SIZE_UNIT (src))
if (TREE_CODE (size) == INTEGER_CST)
max = wi::to_wide (size);
}
}
}
if (bound)
{
/* For strnlen, adjust MIN and MAX as necessary. If the bound
......@@ -1205,7 +1161,7 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
{
/* For a bound in a known range, adjust the range determined
above as necessary. For a bound in some anti-range or
in an unknown range, use the range determined above. */
in an unknown range, use the range determined by callers. */
if (wi::ltu_p (minbound, min))
min = minbound;
if (wi::ltu_p (maxbound, max))
......@@ -1221,6 +1177,79 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
return lhs;
}
/* For an LHS that is an SSA_NAME and for strlen() or strnlen() argument
SRC, set LHS range info to [0, min (N, BOUND)] if SRC refers to
a character array A[N] with unknown length bounded by N, and for
strnlen(), by min (N, BOUND). */
static tree
maybe_set_strlen_range (tree lhs, tree src, tree bound)
{
if (TREE_CODE (lhs) != SSA_NAME
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
return NULL_TREE;
if (TREE_CODE (src) == SSA_NAME)
{
gimple *def = SSA_NAME_DEF_STMT (src);
if (is_gimple_assign (def)
&& gimple_assign_rhs_code (def) == ADDR_EXPR)
src = gimple_assign_rhs1 (def);
}
/* The longest string is PTRDIFF_MAX - 1 bytes including the final
NUL so that the difference between a pointer to just past it and
one to its beginning is positive. */
wide_int max = wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2;
if (TREE_CODE (src) == ADDR_EXPR)
{
/* The last array member of a struct can be bigger than its size
suggests if it's treated as a poor-man's flexible array member. */
src = TREE_OPERAND (src, 0);
if (TREE_CODE (src) != MEM_REF
&& !array_at_struct_end_p (src))
{
tree type = TREE_TYPE (src);
tree size = TYPE_SIZE_UNIT (type);
if (size
&& TREE_CODE (size) == INTEGER_CST
&& !integer_zerop (size))
{
/* Even though such uses of strlen would be undefined,
avoid relying on arrays of arrays in case some genius
decides to call strlen on an unterminated array element
that's followed by a terminated one. Likewise, avoid
assuming that a struct array member is necessarily
nul-terminated (the nul may be in the member that
follows). In those cases, assume that the length
of the string stored in such an array is bounded
by the size of the enclosing object if one can be
determined. */
tree base = get_base_address (src);
if (VAR_P (base))
{
if (tree size = DECL_SIZE_UNIT (base))
if (size
&& TREE_CODE (size) == INTEGER_CST
&& TREE_CODE (TREE_TYPE (base)) != POINTER_TYPE)
max = wi::to_wide (size);
}
}
/* For strlen() the upper bound above is equal to
the longest string that can be stored in the array
(i.e., it accounts for the terminating nul. For
strnlen() bump up the maximum by one since the array
need not be nul-terminated. */
if (!bound && max != 0)
--max;
}
}
return set_strlen_range (lhs, max, bound);
}
/* Handle a strlen call. If strlen of the argument is known, replace
the strlen call with the known value, otherwise remember that strlen
of the argument is stored in the lhs SSA_NAME. */
......
......@@ -23,5 +23,6 @@
extern bool is_strlen_related_p (tree, tree);
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
extern tree set_strlen_range (tree, wide_int, tree = NULL_TREE);
#endif // GCC_TREE_SSA_STRLEN_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment