I think we need to go back and revisit this hunk:

>   /* If the offset is known to be out of bounds, warn, and call strlen at
>      runtime.  */
>   if (eltoff < 0 || eltoff >= maxelts)
>     {
>       /* Suppress multiple warnings for propagated constant strings.  */
>       if (only_value != 2
>           && !TREE_NO_WARNING (arg)
>           && warning_at (loc, OPT_Warray_bounds,
>                          "offset %qwi outside bounds of constant string",
>                          eltoff))
>         { 
>           if (decl)
>             inform (DECL_SOURCE_LOCATION (decl), "%qE declared here", decl);
>           TREE_NO_WARNING (arg) = 1;
>         }
>       return NULL_TREE;
>     }

The problem we have is this is warning inside a utility routine that can
be called many times.

ARG is often going to be an ADDR_EXPR that wraps a _DECL node.  So we'll
end up setting TREE_NO_WARNING on the ADDR_EXPR node.  At first glance
that seems fine, but it's really not sufficient to avoid duplicate warnings.

Consider that we might call get_range_strlen  for ARG again later in the
optimizer pipeline.   That will call the overloaded get_range_strlen
which has the VISITED/RKIND arguments via:

> bool
> get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
> {
>   bitmap visited = NULL;
> 
>   if (!get_range_strlen (arg, &visited, SRK_LENRANGE, pdata, eltsize))

That overload will call get_range_strlen_tree via:

> static bool
> get_range_strlen (tree arg, bitmap *visited,
>                   strlen_range_kind rkind,
>                   c_strlen_data *pdata, unsigned eltsize)
> {
> 
>   if (TREE_CODE (arg) != SSA_NAME)
>     return get_range_strlen_tree (arg, visited, rkind, pdata, eltsize);

get_range_strlen_tree in turn calls c_strlen which may return NULL which
results in stripping the ADDR_EXPR and calling get_range_strlen again via:

>  else
>     {
>       c_strlen_data lendata = { };
>       val = c_strlen (arg, 1, &lendata, eltsize);
> 
>       if (!val && lendata.decl)
>         {
>           /* ARG refers to an unterminated const character array.
>              DATA.DECL with size DATA.LEN.  */
>           val = lendata.minlen;
>           pdata->decl = lendata.decl;
>         }
>     }
> 
>   if (!val && rkind == SRK_LENRANGE)
>     {
>       if (TREE_CODE (arg) == ADDR_EXPR)
>         return get_range_strlen (TREE_OPERAND (arg, 0), visited, rkind,
>                                  pdata, eltsize);

Note that we've stripped the ADDR_EXPR before the call to
get_range_strlen here.  So we have no way to know we've already warned
on this expression and boom it's trivial to get multiple warnings simply
by asking for the range of a node.

This is a great example of why warning from folders and other routines
that may be called more than once (directly or indirectly) is a bad idea.


I think you need to find another place for this warning, preferably
outside the folders and their utility routines.

jeff

Reply via email to