https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89800

            Bug ID: 89800
           Summary: -Waggressive-loop-optimization warning doesn't have
                    useful location
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Keywords: diagnostic
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

Given:

template<typename T>
T foo(T t, int n)
{
  while (n--)
    ++t;
  return t;
}

int bar(int n) { return foo(1, n); }

int main()
{
  return bar(-1);
}

GCC prints:

loop.cc: In function 'int main()':
loop.cc:4:3: warning: iteration 2147483647 invokes undefined behavior
[-Waggressive-loop-optimizations]
    4 |   while (n--)
      |   ^~~~~
loop.cc:4:3: note: within this loop

This isn't very helpful, because the loop isn't in the function 'int main()' as
shown, it's in foo, and there's no indication of how foo was called from main
(there could be several different places in main that indirectly end up calling
foo).

I would expect to see something more like:


loop.cc:4:3: warning: iteration 2147483647 invokes undefined behavior
[-Waggressive-loop-optimizations]
    4 |   while (n--)
      |   ^~~~~
loop.cc:4:3: note: within this loop
loop.cc:2:1 In instantiation of 'foo<T>(T, int) [with T = int]':
loop.cc:9:25  required from 'int bar(int)':
loop.cc:13:10: required from here


A more realistic example is:

#include <array>
#include <forward_list>
#include <iterator>

template<typename T>
typename T::value_type
back(const T& t)
{
  return *std::prev(t.end());
}

int main()
{
  std::array<int, 2> a = { {1, 2} };
  std::forward_list<int> l = {1, 2, 3};
  return back(a) - back(l);
}

With -Wall -Wsystem-headers -O1 this prints:

In file included from
/home/jwakely/gcc/9/include/c++/9.0.1/bits/stl_algobase.h:66,
                 from
/home/jwakely/gcc/9/include/c++/9.0.1/bits/char_traits.h:39,
                 from /home/jwakely/gcc/9/include/c++/9.0.1/string:40,
                 from /home/jwakely/gcc/9/include/c++/9.0.1/stdexcept:39,
                 from /home/jwakely/gcc/9/include/c++/9.0.1/array:39,
                 from prev.cc:1:
/home/jwakely/gcc/9/include/c++/9.0.1/bits/stl_iterator_base_funcs.h: In
function 'int main()':
/home/jwakely/gcc/9/include/c++/9.0.1/bits/stl_iterator_base_funcs.h:153:7:
warning: iteration 9223372036854775806 invokes undefined behavior
[-Waggressive-loop-optimizations]
  153 |       while (__n--)
      |       ^~~~~
/home/jwakely/gcc/9/include/c++/9.0.1/bits/stl_iterator_base_funcs.h:153:7:
note: within this loop

The only location info is the "In file included from" which only shows the
header include stack and the lines of the #include directives, not the call
stack that reached std::__advance where the UB is detected.

The headers suggest that it maybe came from the <array> header, but the back(a)
call is fine, the problem is the back(l) call. (The reason is shows the array
header is  that that's the route by which the <bits/stl_iterator_base_funcs.h>
header gets included, but is not the call stack for the undefined call).

To be useful the warning needs to show the template instantiation context,
something like:

void std::__advance<_InputIterator, _Distance>(_InputIterator&, _Distance,
input_iterator_tag) [with _InputIterator =
std::forward_list<int>::const_iterator, _Distance = int]

void std::advance<_InputIterator, _Distance>(_InputIterator&, _Distance) [with
_InputIterator = std::forward_list<int>::const_iterator, _Distance = int]

void std::prev<_BidirectionalIterator>(_BidirectionalIterator&, ...) [with
_BidirectionalIterator = std::forward_list<int>::const_iterator]

T::value_type back(const T&) [with T = std::forward_list<int>]

prev.cc:16:20 required from here
     return back(a) - back(l);
                      ^^^^^^^

This allows the user to see how the undefined behaviour happened.

(As an aside, should it say "results in undefined behavior" or "has undefined
behavior" not "invokes undefined behavior"? You don't invoke UB, it's not a
function.)

Reply via email to