public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/c++-contracts] c++: GC problem emitting contract functions
@ 2021-07-06 20:44 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2021-07-06 20:44 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:d5c78dacbfa17ea45fe0bb9a0e0929e911b9dcc5

commit d5c78dacbfa17ea45fe0bb9a0e0929e911b9dcc5
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jul 5 19:52:21 2021 -0400

    c++: GC problem emitting contract functions
    
    Here, the copied list of contracts was getting garbage collected between
    compilation of the .pre and .post functions.  Instead of copying the list,
    let's remap the conditions when we are ready to emit them.
    
    gcc/cp/ChangeLog:
    
            * contracts.cc (emit_contract_statement): Just add_stmt.
            (emit_contract_attr): Renamed from above.
            (emit_contract_conditions, emit_assertion): Adjust.
            (remap_and_emit_conditions): New.
            (finish_function_contracts): Use it.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/contracts/contracts-deduced1.C: Use aggressive GC.

Diff:
---
 gcc/cp/contracts.cc                                | 69 +++++++++++++---------
 .../g++.dg/contracts/contracts-deduced1.C          |  2 +-
 2 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 73e6378bf22..1921e062c43 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -1671,19 +1671,26 @@ build_contract_check (tree contract)
   return do_poplevel (scope);
 }
 
-/* Generate the statement for the given contract attribute by adding the
-   statement to the current block. Returns the next contract in the chain.  */
+/* Add the contract statement CONTRACT to the current block if valid.  */
 
-static tree
-emit_contract_statement (tree attr)
+static void
+emit_contract_statement (tree contract)
 {
-  gcc_assert (TREE_CODE (attr) == TREE_LIST);
-  tree contract = CONTRACT_STATEMENT (attr);
-
   /* Only add valid contracts.  */
   if (get_contract_semantic (contract) != CCS_INVALID
       && CONTRACT_CONDITION (contract) != error_mark_node)
     add_stmt (contract);
+}
+
+/* Generate the statement for the given contract attribute by adding the
+   statement to the current block. Returns the next contract in the chain.  */
+
+static tree
+emit_contract_attr (tree attr)
+{
+  gcc_assert (TREE_CODE (attr) == TREE_LIST);
+
+  emit_contract_statement (CONTRACT_STATEMENT (attr));
 
   return CONTRACT_CHAIN (attr);
 }
@@ -1700,7 +1707,7 @@ emit_contract_conditions (tree attrs, tree_code code)
     {
       tree contract = CONTRACT_STATEMENT (attrs);
       if (TREE_CODE (contract) == code)
-	attrs = emit_contract_statement (attrs);
+	attrs = emit_contract_attr (attrs);
       else
 	attrs = CONTRACT_CHAIN (attrs);
     }
@@ -1711,7 +1718,7 @@ emit_contract_conditions (tree attrs, tree_code code)
 void
 emit_assertion (tree attr)
 {
-  emit_contract_statement (attr);
+  emit_contract_attr (attr);
 }
 
 /* Emit statements for precondition attributes.  */
@@ -1730,6 +1737,26 @@ emit_postconditions (tree contracts)
   return emit_contract_conditions (contracts, POSTCONDITION_STMT);
 }
 
+/* We're compiling the pre/postcondition function CONDFN; remap any FN
+   attributes that match CODE and emit them.  */
+
+static void
+remap_and_emit_conditions (tree fn, tree condfn, tree_code code)
+{
+  gcc_assert (code == PRECONDITION_STMT || code == POSTCONDITION_STMT);
+  for (tree attr = DECL_CONTRACTS (fn); attr;
+       attr = CONTRACT_CHAIN (attr))
+    {
+      tree contract = CONTRACT_STATEMENT (attr);
+      if (TREE_CODE (contract) == code)
+	{
+	  contract = copy_node (contract);
+	  remap_contract (fn, condfn, contract, /*duplicate_p=*/false);
+	  emit_contract_statement (contract);
+	}
+    }
+}
+
 /* Converts a contract condition to bool and ensures it has a locaiton.  */
 
 tree
@@ -1860,7 +1887,6 @@ finish_function_contracts (tree fndecl)
     }
 
   int flags = SF_DEFAULT | SF_PRE_PARSED;
-  tree finished_pre = NULL_TREE, finished_post = NULL_TREE;
 
   /* If either the pre or post functions are bad, don't bother emitting
      any contracts.  The program is already ill-formed.  */
@@ -1869,39 +1895,26 @@ finish_function_contracts (tree fndecl)
   if (pre == error_mark_node || post == error_mark_node)
     return;
 
-  /* Create a copy of the contracts with references to fndecl's args replaced
-     with references to either the args of pre or post function.  */
-  tree contracts = copy_list (DECL_CONTRACTS (fndecl));
-  for (tree attr = contracts; attr; attr = CONTRACT_CHAIN (attr))
-    {
-      tree contract = copy_node (CONTRACT_STATEMENT (attr));
-      if (TREE_CODE (contract) == PRECONDITION_STMT)
-	remap_contract (fndecl, pre, contract, /*duplicate_p=*/false);
-      else if (TREE_CODE (contract) == POSTCONDITION_STMT)
-	remap_contract (fndecl, post, contract, /*duplicate_p=*/false);
-      TREE_VALUE (attr) = build_tree_list (NULL_TREE, contract);
-    }
-
   if (pre && DECL_INITIAL (fndecl) != error_mark_node)
     {
       DECL_PENDING_INLINE_P (pre) = false;
       start_preparsed_function (pre, DECL_ATTRIBUTES (pre), flags);
-      emit_preconditions (contracts);
-      finished_pre = finish_function (false);
+      remap_and_emit_conditions (fndecl, pre, PRECONDITION_STMT);
+      tree finished_pre = finish_function (false);
       expand_or_defer_fn (finished_pre);
     }
+
   if (post && DECL_INITIAL (fndecl) != error_mark_node)
     {
       DECL_PENDING_INLINE_P (post) = false;
       start_preparsed_function (post,
 				DECL_ATTRIBUTES (post),
 				flags);
-      emit_postconditions (contracts);
-
+      remap_and_emit_conditions (fndecl, post, POSTCONDITION_STMT);
       if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (post))))
 	finish_return_stmt (get_postcondition_result_parameter (fndecl));
 
-      finished_post = finish_function (false);
+      tree finished_post = finish_function (false);
       expand_or_defer_fn (finished_post);
     }
 }
diff --git a/gcc/testsuite/g++.dg/contracts/contracts-deduced1.C b/gcc/testsuite/g++.dg/contracts/contracts-deduced1.C
index e78ee6b6a9c..200ec734800 100644
--- a/gcc/testsuite/g++.dg/contracts/contracts-deduced1.C
+++ b/gcc/testsuite/g++.dg/contracts/contracts-deduced1.C
@@ -1,7 +1,7 @@
 // Tests to ensure that deduced return types work with postconditions using
 // the return value on defining declarations.
 // { dg-do compile }
-// { dg-options "-std=c++2a -fcontracts" }
+// { dg-options "-std=c++2a -fcontracts --param ggc-min-heapsize=0 --param ggc-min-expand=0" }
 
 auto undeduced(int z)
 {


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-07-06 20:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-06 20:44 [gcc/devel/c++-contracts] c++: GC problem emitting contract functions 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).