if (TREE_CODE (idx) != INTEGER_CST
              && TREE_CODE (argtype) == POINTER_TYPE)
            {
              /* From a pointer (but not array) argument extract the variable
                 index to prevent get_addr_base_and_unit_offset() from failing
                 due to it.  Use it later to compute the non-constant offset
                 into the string and return it to the caller.  */
              varidx = idx;
              ref = TREE_OPERAND (arg, 0);

              tree type = TREE_TYPE (arg);
              if (TREE_CODE (type) == ARRAY_TYPE
                  && TREE_CODE (type) != INTEGER_TYPE)
                return NULL_TREE;
            }

the condition TREE_CODE(type) == ARRAY_TYPE
&& TREE_CODE (type) != INTEGER_TYPE looks funny.
Check for ARRAY_TYPE should imply != INTEGER_TYPE.

  else if (DECL_P (arg))
    {
      array = arg;
      chartype = TREE_TYPE (arg);
    }

chartype is only used in the if (varidx) block, but that is always zero
in this case.

      while (TREE_CODE (chartype) == ARRAY_TYPE
             || TREE_CODE (chartype) == POINTER_TYPE)
        chartype = TREE_TYPE (chartype);

you multiply sizeof(chartype) with varidx but you should probably
use the type of the  TREE_OPERAND (arg, 0); above instead.

this is not in the patch, but I dont like it at all, because it compares the
size of a single initializer against the full size of the array.  But it should
be the innermost enclosing array:

  tree array_size = DECL_SIZE_UNIT (array);
  if (!array_size || TREE_CODE (array_size) != INTEGER_CST)
    return NULL_TREE;

  /* Avoid returning a string that doesn't fit in the array
     it is stored in, like
     const char a[4] = "abcde";
     but do handle those that fit even if they have excess
     initializers, such as in
     const char a[4] = "abc\000\000";
     The excess elements contribute to TREE_STRING_LENGTH()
     but not to strlen().  */
  unsigned HOST_WIDE_INT length
    = strnlen (TREE_STRING_POINTER (init), TREE_STRING_LENGTH (init));
  if (compare_tree_int (array_size, length + 1) < 0)
    return NULL_TREE;

consider the following test case:
$ cat part.c
const char a[2][3][8] = { { "a", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "ccc"},
                          { "dddd", "eeeee", "ffffff" } };

int main ()
{
  int n = __builtin_strlen (&a[0][1][0]);

  if (n == 30)
    __builtin_abort ();
}

11413     if (!init || TREE_CODE (init) != STRING_CST)
(gdb) call debug(init)
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
(gdb) n
11416     tree array_size = DECL_SIZE_UNIT (array);
(gdb) n
11417     if (!array_size || TREE_CODE (array_size) != INTEGER_CST)
(gdb) call debug(array_size)
48
(gdb) n
11429       = strnlen (TREE_STRING_POINTER (init), TREE_STRING_LENGTH (init));
(gdb) n
11430     if (compare_tree_int (array_size, length + 1) < 0)
(gdb) n
11433     *ptr_offset = offset;
(gdb) 




Bernd.

Reply via email to