On 8/23/26 5:22 PM, Wang Jinghao wrote:
On Fri, Aug 21, 2026 at 7:56 PM Waffl3x <[email protected]> wrote:

Iains pointed out this patch to me after I submitted mine. Didn't mean
to duplicate work, sorry!
Don't mind :P

On Monday, August 17th, 2026 at 1:40 PM, Jason Merrill <[email protected]> wrote:
On 8/14/26 4:33 PM, Wang Jinghao wrote:
For precondition and postcondition without a result binding, whether
the return type is auto is irrelevant to the condition expression, so
type conversions should be completed immediately.

     PR c++/125537

gcc/cp/ChangeLog:

     * pt.cc (tsubst_contract): Keep template processing enabled
     only for postconditions with an undeduced result binding.

Hmm, I notice this is still a different condition from
cp_parser_late_contract_condition and rebuild_postconditions, which only
check whether there's a result binding, not whether it's auto.  They
ought to agree on the condition for treating the postcondition as a
pseudo-template.

By the time you're in rebuild_postconditions I believe the placeholder
return type is gone. It bails out early 'if the return type is
undeduced', I haven't looked at cp_parser_late_contract_condition
enough though so maybe there are issues on that side.

gcc/testsuite/ChangeLog:

     * g++.dg/contracts/cpp26/pr125537.C: New test.

Please name tests by what they are testing, not just by PR number.  So
this could be template-post1.C.

Jason

I guess I'll have to fix my patches as well then.
I have a follow up patch that implements this part, perhaps it might
be useful to you.  This should also be one of the causes of the
ICE in PR125574.
I combined this with the earlier patch and pushed it, like so:

But somehow I didn't notice until after pushing that contracts-class1.C was failing with a -Wreturn-type warning. Did you mean for the test to be different somehow?

Jason
From 943089ca86f81fb6eba004af17a8d714b3b8b35b Mon Sep 17 00:00:00 2001
From: Wang Jinghao <[email protected]>
Date: Wed, 26 Aug 2026 08:39:17 -0700
Subject: [PATCH] c++/contracts: unify condition for pseudo-template mode
 [PR125537]
To: [email protected]

These three functions had different conditions for when a postcondition was
parsed/substituted in pseudo-template mode, leading to problems with trying
to substitute non-template trees.  Consistently use/expect this approach
only for postconditions with result identifiers and deduced return types.

	PR c++/125537

gcc/cp/ChangeLog:

	* pt.cc (tsubst_contract): Keep template processing enabled
	only for postconditions with an undeduced result binding.
	* contracts.cc (rebuild_postconditions): Only rebuild
	undeduced result variable.
	* parser.cc (cp_parser_late_contract_condition): Enable
	pseudo-template mode only for result bindings whose return
	type has not yet been deduced.  Do not immediately rebuild
	postconditions that have already completed late parsing.

gcc/testsuite/ChangeLog:

	* g++.dg/contracts/cpp26/template-post1.C: New test.
	* g++.dg/contracts/cpp26/contracts-class1.C: New test.
---
 gcc/cp/contracts.cc                            |  7 ++++++-
 gcc/cp/parser.cc                               | 10 +++++-----
 gcc/cp/pt.cc                                   | 10 ++++++----
 .../g++.dg/contracts/cpp26/contracts-class1.C  | 14 ++++++++++++++
 .../g++.dg/contracts/cpp26/template-post1.C    | 18 ++++++++++++++++++
 5 files changed, 49 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/contracts-class1.C
 create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/template-post1.C

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index 8bd2a8df5b9..4ae40dfaba0 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -1982,7 +1982,7 @@ rebuild_postconditions (tree fndecl)
   tree type = TREE_TYPE (TREE_TYPE (fndecl));
 
   /* If the return type is undeduced, defer until later.  */
-  if (TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+  if (type_uses_auto (type))
     return;
 
   tree contract_spec = get_fn_contract_specifiers (fndecl);
@@ -2019,6 +2019,11 @@ rebuild_postconditions (tree fndecl)
 	  continue;
 	}
 
+      /* A concrete late-parsed result variable still needs validation, but
+	 not rebuilding.  Rebuild only one whose type was undeduced.  */
+      if (!type_uses_auto (TREE_TYPE (oldvar)))
+	continue;
+
       /* "Instantiate" the result variable using the known type.  */
       tree newvar = copy_node (oldvar);
       TREE_TYPE (newvar) = type;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index f40e335b9d0..967ba3fd542 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -33824,21 +33824,21 @@ cp_parser_late_contract_condition (cp_parser *parser, tree fn, tree contract)
   processing_postcondition = POSTCONDITION_P (contract);
   /* Build a fake variable for the result identifier.  */
   tree result = NULL_TREE;
+  const bool undeduced_result_type_p
+    = r_ident && type_uses_auto (type);
   if (r_ident)
     {
       cp_expr result_id (r_ident, r_loc);
       result = make_postcondition_variable (result_id, type);
-      ++processing_template_decl;
+      if (undeduced_result_type_p)
+	++processing_template_decl;
     }
   cp_expr parsed_condition = cp_parser_conditional_expression (parser);
   /* Commit to changes.  */
   update_late_contract (contract, result, parsed_condition);
-  if (r_ident)
+  if (undeduced_result_type_p)
     --processing_template_decl;
 
-  /* Rebuild the postcondition since we didn't do it in grokfndecl. */
-  rebuild_postconditions (fn);
-
   /* Leave our temporary scope for the postcondition result.  */
   processing_postcondition = old_pc;
   gcc_checking_assert (scope_chain && scope_chain->bindings
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d2be3790961..6b8fbcd1c14 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12398,12 +12398,14 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
 	  return invalidate_contract (r);
     }
 
-  /* Instantiate the condition.  If the return type is undeduced, process
-     the expression as if inside a template to avoid spurious type errors.  */
+  /* Instantiate the condition.  If the postcondition has a result binding
+     whose type is undeduced, process the expression as if inside a template to
+     avoid spurious type errors.  */
   begin_scope (sk_contract, decl);
   bool old_pc = processing_postcondition;
   processing_postcondition = POSTCONDITION_P (t);
-  if (auto_p)
+  const bool undeduced_result_type_p = auto_p && newvar;
+  if (undeduced_result_type_p)
     ++processing_template_decl;
   if (newvar)
     /* Make the variable available for lookup.  */
@@ -12429,7 +12431,7 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
      && !type_dependent_expression_p (CONTRACT_ASSERTION_KIND (r))
      && !type_dependent_expression_p (CONTRACT_COMMENT (r)));
 
-  if (auto_p)
+  if (undeduced_result_type_p)
     --processing_template_decl;
   processing_postcondition = old_pc;
   gcc_checking_assert (scope_chain && scope_chain->bindings
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/contracts-class1.C b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-class1.C
new file mode 100644
index 00000000000..a878e212f1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/contracts-class1.C
@@ -0,0 +1,14 @@
+// Check whether deferred deduction works correctly when post conditions
+// are used in member functions.
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-fcontracts" }
+
+bool check (bool b) { return b; }
+
+class S
+{
+  bool f ()
+    post (r: check (r))
+    post (r: r)
+  {}
+};
diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/template-post1.C b/gcc/testsuite/g++.dg/contracts/cpp26/template-post1.C
new file mode 100644
index 00000000000..876879c253e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/contracts/cpp26/template-post1.C
@@ -0,0 +1,18 @@
+// PR c++/125537
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-fcontracts" }
+
+template<typename>
+  auto f (const bool b)
+    pre (b)
+    post (b)
+    post (r: r)
+  {
+    return b;
+  }
+
+
+int main ()
+{
+  f<bool> (true);
+}
-- 
2.55.0

Reply via email to