public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PR69315] enable finish_function to recurse for constexpr functions
@ 2016-01-26 17:12 Alexandre Oliva
  2016-02-10 21:22 ` Alexandre Oliva
  2016-03-22 21:36 ` Jason Merrill
  0 siblings, 2 replies; 7+ messages in thread
From: Alexandre Oliva @ 2016-01-26 17:12 UTC (permalink / raw)
  To: gcc-patches

We don't want finish_function to be called recursively from mark_used.
However, it's desirable and necessary to call itself recursively when
performing delayed folding, because that may have to instantiate and
evaluate constexpr template functions.

So, arrange for finish_function to accept being called recursively
during delayed folding, save and restore the controlling variables,
and process the deferred mark_used calls only when the outermost call
completes.

Regstrapped on x86_64-linux-gnu and i686-linux-gnu.  Ok to install?

for  gcc/cp/ChangeLog

	PR c++/69315
	* decl.c (is_folding_function): New variable.
	(finish_function): Test, save and set it.

for  gcc/testsuite/ChangeLog

	PR c++/69315
	* g++.dg/pr69315.C: New.
---
 gcc/cp/decl.c                  |   31 +++++++++++++++++++++++++------
 gcc/testsuite/g++.dg/pr69315.C |   34 ++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr69315.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f4604b6..65eff2f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -227,10 +227,14 @@ struct GTY((for_user)) named_label_entry {
    function, two inside the body of a function in a local class, etc.)  */
 int function_depth;
 
-/* To avoid unwanted recursion, finish_function defers all mark_used calls
-   encountered during its execution until it finishes.  */
+/* To avoid unwanted recursion, finish_function defers all mark_used
+   calls encountered during its execution until it finishes.
+   finish_function refuses to be called recursively, unless the
+   recursion occurs during folding, which often requires instantiating
+   and evaluating template functions.  */
 bool defer_mark_used_calls;
 vec<tree, va_gc> *deferred_mark_used_calls;
+static bool is_folding_function;
 
 /* States indicating how grokdeclarator() should handle declspecs marked
    with __attribute__((deprecated)).  An object declared as
@@ -14528,8 +14532,11 @@ finish_function (int flags)
   if (c_dialect_objc ())
     objc_finish_function ();
 
-  gcc_assert (!defer_mark_used_calls);
+  gcc_assert (!defer_mark_used_calls
+	      || (is_folding_function && DECL_DECLARED_CONSTEXPR_P (fndecl)));
   defer_mark_used_calls = true;
+  bool save_folding_function = is_folding_function;
+  is_folding_function = false;
 
   record_key_method_defined (fndecl);
 
@@ -14636,7 +14643,14 @@ finish_function (int flags)
 
   /* Perform delayed folding before NRV transformation.  */
   if (!processing_template_decl)
-    cp_fold_function (fndecl);
+    {
+      is_folding_function = true;
+      cp_fold_function (fndecl);
+      /* Check that our controlling variables were restored to the
+	 expect state.  */
+      gcc_assert (is_folding_function && defer_mark_used_calls);
+      is_folding_function = false;
+    }
 
   /* Set up the named return value optimization, if we can.  Candidate
      variables are selected in check_return_expr.  */
@@ -14780,8 +14794,13 @@ finish_function (int flags)
   /* Clean up.  */
   current_function_decl = NULL_TREE;
 
-  defer_mark_used_calls = false;
-  if (deferred_mark_used_calls)
+  is_folding_function = save_folding_function;
+  /* Iff we were called recursively for a constexpr function,
+     is_folding_function was just restored to TRUE.  If we weren't
+     called recursively, it was restored to FALSE.  That's just how
+     defer_mark_used_call ought to be set.  */
+  defer_mark_used_calls = is_folding_function;
+  if (!defer_mark_used_calls && deferred_mark_used_calls)
     {
       unsigned int i;
       tree decl;
diff --git a/gcc/testsuite/g++.dg/pr69315.C b/gcc/testsuite/g++.dg/pr69315.C
new file mode 100644
index 0000000..28975b6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr69315.C
@@ -0,0 +1,34 @@
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+// Template instantiation and evaluation for folding within
+// finish_function may call finish_function recursively.
+// Make sure we don't reject or delay that sort of recursion.
+
+template <bool> struct Iter;
+
+struct Arg {
+  Iter<true> begin();
+  Iter<true> end();
+};
+
+template <bool> struct Iter {
+  int operator*();
+  Iter operator++();
+  template <bool C1, bool C2> friend constexpr bool operator==(Iter<C1>, Iter<C2>);
+  template <bool C1, bool C2> friend constexpr bool operator!=(Iter<C1>, Iter<C2>);
+};
+
+void func(Arg a) {
+  for (auto ch : a) {
+    a.begin() == a.end();
+  }
+}
+
+template <bool C1, bool C2> constexpr bool operator==(Iter<C1>, Iter<C2>) {
+  return true;
+}
+
+template <bool C1, bool C2> constexpr bool operator!=(Iter<C1> a, Iter<C2> b) {
+  return a == b;
+}

-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-03-23 17:45 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-26 17:12 [PR69315] enable finish_function to recurse for constexpr functions Alexandre Oliva
2016-02-10 21:22 ` Alexandre Oliva
2016-02-24 12:56   ` Alexandre Oliva
2016-03-22 21:36 ` Jason Merrill
2016-03-23 14:01   ` Jakub Jelinek
2016-03-23 16:24     ` Jakub Jelinek
2016-03-23 18:22       ` Jason Merrill

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).