c++: Implement -Wrange-loop-construct [PR94695]
authorMarek Polacek <polacek@redhat.com>
Thu, 24 Sep 2020 18:30:50 +0000 (14:30 -0400)
committerMarek Polacek <polacek@redhat.com>
Tue, 29 Sep 2020 23:03:04 +0000 (19:03 -0400)
commit969baf03acd8124345617cea125b148568c7370a
tree0188d91dea5c97f873a1f94023f86f91449ec3a9
parent01852cc865c9c53fa3ba6627c1b7abd2446f48c1
c++: Implement -Wrange-loop-construct [PR94695]

This new warning can be used to prevent expensive copies inside range-based
for-loops, for instance:

  struct S { char arr[128]; };
  void fn () {
    S arr[5];
    for (const auto x : arr) {  }
  }

where auto deduces to S and then we copy the big S in every iteration.
Using "const auto &x" would not incur such a copy.  With this patch the
compiler will warn:

q.C:4:19: warning: loop variable 'x' creates a copy from type 'const S' [-Wrange-loop-construct]
    4 |   for (const auto x : arr) {  }
      |                   ^
q.C:4:19: note: use reference type 'const S&' to prevent copying
    4 |   for (const auto x : arr) {  }
      |                   ^
      |                   &

As per Clang, this warning is suppressed for trivially copyable types
whose size does not exceed 64B.  The tricky part of the patch was how
to figure out if using a reference would have prevented a copy.  To
that point, I'm using the new function called ref_conv_binds_directly_p.

This warning is enabled by -Wall.  Further warnings of similar nature
should follow soon.

gcc/c-family/ChangeLog:

PR c++/94695
* c.opt (Wrange-loop-construct): New option.

gcc/cp/ChangeLog:

PR c++/94695
* call.c (ref_conv_binds_directly_p): New function.
* cp-tree.h (ref_conv_binds_directly_p): Declare.
* parser.c (warn_for_range_copy): New function.
(cp_convert_range_for): Call it.

gcc/ChangeLog:

PR c++/94695
* doc/invoke.texi: Document -Wrange-loop-construct.

gcc/testsuite/ChangeLog:

PR c++/94695
* g++.dg/warn/Wrange-loop-construct.C: New test.
gcc/c-family/c.opt
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/warn/Wrange-loop-construct.C [new file with mode: 0644]