diff options
author | Marek Polacek <polacek@redhat.com> | 2020-09-24 14:30:50 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-09-29 19:03:04 -0400 |
commit | 969baf03acd8124345617cea125b148568c7370a (patch) | |
tree | 0188d91dea5c97f873a1f94023f86f91449ec3a9 /gcc/cp/call.c | |
parent | 01852cc865c9c53fa3ba6627c1b7abd2446f48c1 (diff) | |
download | gcc-969baf03acd8124345617cea125b148568c7370a.zip gcc-969baf03acd8124345617cea125b148568c7370a.tar.gz gcc-969baf03acd8124345617cea125b148568c7370a.tar.bz2 |
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.
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r-- | gcc/cp/call.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5606389..1e5fffe 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8429,6 +8429,28 @@ conv_binds_ref_to_prvalue (conversion *c) return false; } +/* True iff converting EXPR to a reference type TYPE does not involve + creating a temporary. */ + +bool +ref_conv_binds_directly_p (tree type, tree expr) +{ + gcc_assert (TYPE_REF_P (type)); + + /* Get the high-water mark for the CONVERSION_OBSTACK. */ + void *p = conversion_obstack_alloc (0); + + conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr, + /*c_cast_p=*/false, + LOOKUP_IMPLICIT, tf_none); + bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv); + + /* Free all the conversions we allocated. */ + obstack_free (&conversion_obstack, p); + + return ret; +} + /* Call the trivial destructor for INSTANCE, which can be either an lvalue of class type or a pointer to class type. If NO_PTR_DEREF is true and INSTANCE has pointer type, clobber the pointer rather than what it points |