public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/redhat/heads/gcc-8-branch)] Reject tail calls that read from an escaped RESULT_DECL [PR90313]
@ 2020-09-17 16:45 Jakub Jelinek
0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2020-09-17 16:45 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:2207b426bb5607783885b2fe7e9b87a815ff6565
commit 2207b426bb5607783885b2fe7e9b87a815ff6565
Author: Richard Sandiford <richard.sandiford@arm.com>
Date: Fri Aug 9 09:37:55 2019 +0000
Reject tail calls that read from an escaped RESULT_DECL [PR90313]
In this PR we have two return paths from a function "map". The common
code sets <result> to the value returned by one path, while the other
path does:
<retval> = map (&<retval>, ...);
We treated this call as tail recursion, losing the copy semantics
on the value returned by the recursive call.
We'd correctly reject the same thing for variables:
local = map (&local, ...);
The problem is that RESULT_DECLs didn't get the same treatment.
2020-02-25 Richard Sandiford <richard.sandiford@arm.com>
gcc/
Backport from mainline
2019-08-09 Richard Sandiford <richard.sandiford@arm.com>
PR middle-end/90313
* tree-tailcall.c (find_tail_calls): Reject calls that might
read from an escaped RESULT_DECL.
gcc/testsuite/
PR middle-end/90313
* g++.dg/torture/pr90313.cc: New test.
Diff:
---
gcc/ChangeLog | 9 +++++++++
gcc/testsuite/ChangeLog | 5 +++++
gcc/testsuite/g++.dg/torture/pr90313.cc | 33 +++++++++++++++++++++++++++++++++
gcc/tree-tailcall.c | 29 +++++++++++++++++++++++++++++
4 files changed, 76 insertions(+)
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 392108630cc..77c18b12e95 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2020-02-25 Richard Sandiford <richard.sandiford@arm.com>
+
+ Backport from mainline
+ 2019-08-09 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR middle-end/90313
+ * tree-tailcall.c (find_tail_calls): Reject calls that might
+ read from an escaped RESULT_DECL.
+
2020-02-24 Jason Merrill <jason@redhat.com>
PR c++/92003
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7d822b619fc..af503fccdc6 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2020-02-25 Richard Sandiford <richard.sandiford@arm.com>
+
+ PR middle-end/90313
+ * g++.dg/torture/pr90313.cc: New test.
+
2020-02-23 Peter Bergner <bergner@linux.ibm.com>
Backport from master
diff --git a/gcc/testsuite/g++.dg/torture/pr90313.cc b/gcc/testsuite/g++.dg/torture/pr90313.cc
new file mode 100644
index 00000000000..d9f183a2939
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr90313.cc
@@ -0,0 +1,33 @@
+// { dg-do run }
+
+#include <stddef.h>
+
+namespace std {
+ template<typename T, size_t N> struct array {
+ T elems[N];
+ const T &operator[](size_t i) const { return elems[i]; }
+ };
+}
+
+using Coordinates = std::array<double, 3>;
+
+Coordinates map(const Coordinates &c, size_t level)
+{
+ Coordinates result{ c[1], c[2], c[0] };
+
+ if (level != 0)
+ result = map (result, level - 1);
+
+ return result;
+}
+
+int main()
+{
+ Coordinates vecOfCoordinates = { 1.0, 2.0, 3.0 };
+
+ auto result = map(vecOfCoordinates, 1);
+ if (result[0] != 3 || result[1] != 1 || result[2] != 2)
+ __builtin_abort ();
+
+ return 0;
+}
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index de18f9bcf87..aeca4e559c6 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -479,6 +479,35 @@ find_tail_calls (basic_block bb, struct tailcall **ret)
&& !stmt_can_throw_external (stmt))
return;
+ /* If the function returns a value, then at present, the tail call
+ must return the same type of value. There is conceptually a copy
+ between the object returned by the tail call candidate and the
+ object returned by CFUN itself.
+
+ This means that if we have:
+
+ lhs = f (&<retval>); // f reads from <retval>
+ // (lhs is usually also <retval>)
+
+ there is a copy between the temporary object returned by f and lhs,
+ meaning that any use of <retval> in f occurs before the assignment
+ to lhs begins. Thus the <retval> that is live on entry to the call
+ to f is really an independent local variable V that happens to be
+ stored in the RESULT_DECL rather than a local VAR_DECL.
+
+ Turning this into a tail call would remove the copy and make the
+ lifetimes of the return value and V overlap. The same applies to
+ tail recursion, since if f can read from <retval>, we have to assume
+ that CFUN might already have written to <retval> before the call.
+
+ The problem doesn't apply when <retval> is passed by value, but that
+ isn't a case we handle anyway. */
+ tree result_decl = DECL_RESULT (cfun->decl);
+ if (result_decl
+ && may_be_aliased (result_decl)
+ && ref_maybe_used_by_stmt_p (call, result_decl))
+ return;
+
/* We found the call, check whether it is suitable. */
tail_recursion = false;
func = gimple_call_fndecl (call);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-09-17 16:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-17 16:45 [gcc(refs/vendors/redhat/heads/gcc-8-branch)] Reject tail calls that read from an escaped RESULT_DECL [PR90313] Jakub Jelinek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).