c++, contracts: Account for lambda captures in pre/post [PR124648].

Message ID 20260408095354.49694-1-iain@sandoe.co.uk
State New
Headers
Series c++, contracts: Account for lambda captures in pre/post [PR124648]. |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed

Commit Message

Iain Sandoe April 8, 2026, 9:53 a.m. UTC
  This is a second issue that appears once the exclusion of implicit
lambda captures is fixed.  Tested on x86_64-darwin, powerpc64le-linux
OK for trunk/when?
thanks
Iain

--- 8< ---

When we have lambda captures, they appear in the vars slot of a bind
expression at the outer operator() body.

We need these to be visible for any pre or post conditions that might
use them, therefore (when a lambda has captures) nest the application
of contract pre and post conditions within the lambda outer bind
expression.

	PR c++/124648

gcc/cp/ChangeLog:

	* contracts.cc (maybe_apply_function_contracts): Nest pre and
	post conditions inside the outer bind expression of a lambda
	with captures.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
---
 gcc/cp/contracts.cc | 12 ++++++++++++
 1 file changed, 12 insertions(+)
  

Comments

Jason Merrill April 9, 2026, 6:51 p.m. UTC | #1
On 4/8/26 5:53 AM, Iain Sandoe wrote:
> This is a second issue that appears once the exclusion of implicit
> lambda captures is fixed.  Tested on x86_64-darwin, powerpc64le-linux
> OK for trunk/when?
> thanks
> Iain
> 
> --- 8< ---
> 
> When we have lambda captures, they appear in the vars slot of a bind
> expression at the outer operator() body.
> 
> We need these to be visible for any pre or post conditions that might
> use them, therefore (when a lambda has captures) nest the application
> of contract pre and post conditions within the lambda outer bind
> expression.
> 
> 	PR c++/124648
> 
> gcc/cp/ChangeLog:
> 
> 	* contracts.cc (maybe_apply_function_contracts): Nest pre and
> 	post conditions inside the outer bind expression of a lambda
> 	with captures.
> 
> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
> ---
>   gcc/cp/contracts.cc | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 
> diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
> index d2dba3c62e6..760327d2020 100644
> --- a/gcc/cp/contracts.cc
> +++ b/gcc/cp/contracts.cc
> @@ -1352,6 +1352,18 @@ maybe_apply_function_contracts (tree fndecl)
>         DECL_SAVED_TREE (fndecl) = push_stmt_list ();
>       }
>   
> +  /* If we have a lambda with captures, ensure that those captures are in-
> +     scope for pre and post conditions.  */
> +  if (LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))

This could be LAMBDA_FUNCTION_P.  OK with that change.

> +      && TREE_CODE (fnbody) == BIND_EXPR)
> +    {
> +      tree extract = BIND_EXPR_BODY (fnbody);
> +      BIND_EXPR_BODY (fnbody) = NULL_TREE;
> +      add_stmt (fnbody);
> +      BIND_EXPR_BODY (fnbody) = push_stmt_list ();
> +      fnbody = extract;
> +    }
> +
>     /* Now add the pre and post conditions to the existing function body.
>        This copies the approach used for function try blocks.  */
>     tree compound_stmt = begin_compound_stmt (0);
  

Patch

diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index d2dba3c62e6..760327d2020 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -1352,6 +1352,18 @@  maybe_apply_function_contracts (tree fndecl)
       DECL_SAVED_TREE (fndecl) = push_stmt_list ();
     }
 
+  /* If we have a lambda with captures, ensure that those captures are in-
+     scope for pre and post conditions.  */
+  if (LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))
+      && TREE_CODE (fnbody) == BIND_EXPR)
+    {
+      tree extract = BIND_EXPR_BODY (fnbody);
+      BIND_EXPR_BODY (fnbody) = NULL_TREE;
+      add_stmt (fnbody);
+      BIND_EXPR_BODY (fnbody) = push_stmt_list ();
+      fnbody = extract;
+    }
+
   /* Now add the pre and post conditions to the existing function body.
      This copies the approach used for function try blocks.  */
   tree compound_stmt = begin_compound_stmt (0);