On 8/14/26 4:40 PM, Wang Jinghao wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu.

-- >8 --

Contract conditions are parsed outside the function body, so
`at_function_scope_p()' is false when their parameter pack expansions
are formed.  However, function parameter packs in contract conditions
should use local specializations during substitution, just as they do
within a function body.

Does it work to change at_function_scope_p() to local_bindings_p()? The latter seems to be the more relevant question.

...it seems not yet, because local_bindings_p wrongly returns false for contract scope, so we need to move sk_contract before sk_function_parms in scope_kind, as attached.

gcc/testsuite/ChangeLog:

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

So perhaps fold1.C.
From fa87b30937d166715324eb1a4b6b25e501e0c8b6 Mon Sep 17 00:00:00 2001
From: Jason Merrill <[email protected]>
Date: Mon, 17 Aug 2026 09:06:09 -0400
Subject: [PATCH] c++: correct local_bindings_p for contracts
To: [email protected]

gcc/cp/ChangeLog:

	* name-lookup.h (enum scope_kind): Move sk_contract before
	sk_function_parms.
	* pt.cc (make_pack_expansion): Use local_bindings_p.
---
 gcc/cp/name-lookup.h | 6 ++++--
 gcc/cp/pt.cc         | 5 ++---
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index a0e7e10795e..af3fd927f3d 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -239,6 +239,8 @@ enum scope_kind {
   sk_cond,	     /* The scope of the variable declared in the condition
 			of an if or switch statement.  */
   sk_stmt_expr,	     /* GNU statement expression block.  */
+  sk_contract,	     /* A C++26 contract-assertion scope.
+			[basic.scope.contract] */
   sk_function_parms, /* The scope containing function parameters.  */
   sk_class,	     /* The scope containing the members of a class.  */
   sk_scoped_enum,    /* The scope containing the enumerators of a C++11
@@ -253,8 +255,8 @@ enum scope_kind {
   sk_transaction,    /* A synchronized or atomic statement.  */
   sk_omp,	     /* An OpenMP structured block.  */
   sk_lambda,	     /* A lambda scope.  */
-  sk_contract,	     /* A C++26 contract-assertion scope.
-			[basic.scope.contract] */
+  /* Note that scopes for which local_bindings_p should be true must precede
+     sk_function_parms.  */
   sk_count	     /* Number of scope_kind enumerations.  */
 };
 
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 50f9fae49d1..6791795e26a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4402,7 +4402,7 @@ make_pack_expansion (tree arg, tsubst_flags_t complain)
       purpose = cxx_make_type (TYPE_PACK_EXPANSION);
       PACK_EXPANSION_PATTERN (purpose) = TREE_PURPOSE (arg);
       PACK_EXPANSION_PARAMETER_PACKS (purpose) = parameter_packs;
-      PACK_EXPANSION_LOCAL_P (purpose) = at_function_scope_p ();
+      PACK_EXPANSION_LOCAL_P (purpose) = local_bindings_p ();
 
       /* Just use structural equality for these TYPE_PACK_EXPANSIONS;
 	 they will rarely be compared to anything.  */
@@ -4455,8 +4455,7 @@ make_pack_expansion (tree arg, tsubst_flags_t complain)
   /* Contract conditions are parsed outside a function body but function
      parameter pack expansions in them must use the instantiated parameters
      rather than dummy declarations.  */
-  PACK_EXPANSION_LOCAL_P (result)
-    = at_function_scope_p () || processing_contract_condition;
+  PACK_EXPANSION_LOCAL_P (result) = local_bindings_p ();
   if (ppd.found_extra_args_tree_p)
     /* If the pattern of this pack expansion contains a subtree that has
        the extra args mechanism for avoiding partial instantiation, then
-- 
2.55.0

Reply via email to