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